feat: 使用SignalR实时发送示波器数据,并美化示波器界面
This commit is contained in:
@@ -1,109 +1,336 @@
|
||||
<template>
|
||||
<div class="bg-base-100 flex flex-col gap-4">
|
||||
<!-- 波形展示 -->
|
||||
<div class="card bg-base-200 shadow-xl mx-5">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title flex flex-row justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<Activity class="w-5 h-5" />
|
||||
波形显示
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="btn btn-sm btn-warning" @click="osc.stopCapture" :disabled="!osc.isCapturing.value">
|
||||
停止捕获
|
||||
</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="btn btn-sm btn-error" @click="osc.clearOscilloscopeData">
|
||||
清空
|
||||
<div
|
||||
class="oscilloscope-container min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800 p-4"
|
||||
>
|
||||
<!-- 顶部状态栏 -->
|
||||
<div class="status-bar mb-6">
|
||||
<div
|
||||
class="card bg-white/80 dark:bg-slate-800/80 backdrop-blur-lg shadow-xl border border-white/20"
|
||||
>
|
||||
<div class="card-body p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="status-indicator flex items-center gap-2">
|
||||
<div class="relative">
|
||||
<Activity class="w-6 h-6 text-blue-600" />
|
||||
<div
|
||||
v-if="osc.isCapturing.value"
|
||||
class="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full animate-pulse"
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<h1
|
||||
class="text-xl font-bold text-slate-800 dark:text-slate-200"
|
||||
>
|
||||
数字示波器
|
||||
</h1>
|
||||
<p class="text-sm text-slate-600 dark:text-slate-400">
|
||||
{{ osc.isCapturing.value ? "正在采集数据..." : "待机状态" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-buttons flex items-center gap-3">
|
||||
<button
|
||||
class="btn-gradient"
|
||||
:class="osc.isCapturing.value ? 'btn-stop' : 'btn-start'"
|
||||
@click="toggleCapture"
|
||||
>
|
||||
<component
|
||||
:is="osc.isCapturing.value ? Square : Play"
|
||||
class="w-5 h-5"
|
||||
/>
|
||||
{{ osc.isCapturing.value ? "停止采集" : "开始采集" }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn-clear"
|
||||
@click="osc.clearOscilloscopeData"
|
||||
:disabled="osc.isCapturing.value"
|
||||
>
|
||||
<Trash2 class="w-4 h-4" />
|
||||
清空数据
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</h2>
|
||||
<OscilloscopeWaveformDisplay />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 示波器配置 -->
|
||||
<div class="card bg-base-200 shadow-xl mx-5">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">示波器配置</h2>
|
||||
<form class="flex flex-col gap-2" @submit.prevent="applyConfiguration">
|
||||
<div class="flex flex-row items-center justify-between gap-4">
|
||||
<label>
|
||||
边沿触发:
|
||||
<select v-model="osc.config.triggerRisingEdge" class="select select-bordered w-24">
|
||||
<option :value="true">上升沿</option>
|
||||
<option :value="false">下降沿</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
触发电平:
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="range" min="0" max="255" step="1" v-model="osc.config.triggerLevel"
|
||||
class="range range-sm w-50" />
|
||||
<input type="number" v-model="osc.config.triggerLevel" min="0" max="255"
|
||||
class="input input-bordered w-24" />
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-content grid grid-cols-1 xl:grid-cols-4 gap-6">
|
||||
<!-- 波形显示区域 - 占据大部分空间 -->
|
||||
<div class="waveform-section xl:col-span-3">
|
||||
<div
|
||||
class="card bg-white/80 dark:bg-slate-800/80 backdrop-blur-lg shadow-xl border border-white/20 h-full"
|
||||
>
|
||||
<div class="card-body p-6">
|
||||
<div class="waveform-header flex items-center justify-between mb-4">
|
||||
<h2
|
||||
class="text-lg font-semibold text-slate-800 dark:text-slate-200 flex items-center gap-2"
|
||||
>
|
||||
<Zap class="w-5 h-5 text-yellow-500" />
|
||||
波形显示
|
||||
</h2>
|
||||
<div class="waveform-controls flex items-center gap-2">
|
||||
<div
|
||||
class="refresh-indicator flex items-center gap-2 text-sm text-slate-600 dark:text-slate-400"
|
||||
>
|
||||
<div
|
||||
class="w-2 h-2 bg-green-500 rounded-full animate-pulse"
|
||||
></div>
|
||||
{{ refreshCycle }}ms 刷新
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label>
|
||||
水平偏移:
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="range" min="0" max="1000" step="1" v-model="osc.config.horizontalShift"
|
||||
class="range range-sm w-50" />
|
||||
<input type="number" v-model="osc.config.horizontalShift" min="0" max="1000"
|
||||
class="input input-bordered w-24" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="waveform-display h-96 lg:h-[500px] relative overflow-hidden rounded-lg border border-slate-200 dark:border-slate-700"
|
||||
>
|
||||
<OscilloscopeWaveformDisplay class="w-full h-full" />
|
||||
|
||||
<!-- 数据覆盖层 -->
|
||||
<div
|
||||
v-if="osc.isCapturing.value && !hasWaveformData"
|
||||
class="absolute inset-0 flex items-center justify-center bg-slate-50/50 dark:bg-slate-900/50 backdrop-blur-sm"
|
||||
>
|
||||
<div class="text-center space-y-4">
|
||||
<div class="w-16 h-16 mx-auto text-slate-400">
|
||||
<Activity class="w-full h-full" />
|
||||
</div>
|
||||
<p class="text-slate-600 dark:text-slate-400">
|
||||
等待波形数据...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label>
|
||||
抽取率:
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="range" min="0" max="100" step="1" v-model="osc.config.decimationRate"
|
||||
class="range range-sm w-50" />
|
||||
<input type="number" v-model="osc.config.decimationRate" min="0" max="100"
|
||||
class="input input-bordered w-24" />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex gap-4">
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2 mt-2">
|
||||
<label>
|
||||
刷新间隔(ms):
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="range" min="100" max="3000" step="100" v-model="osc.refreshIntervalMs.value"
|
||||
class="range range-sm w-50" />
|
||||
<input type="number" min="100" max="3000" step="100" v-model="osc.refreshIntervalMs.value"
|
||||
class="input input-bordered w-24" />
|
||||
</div>
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="btn btn-primary" type="submit" :disabled="osc.isApplying.value || osc.isCapturing.value">
|
||||
应用配置
|
||||
</button>
|
||||
<button class="btn btn-secondary" type="button" @click="osc.resetConfiguration"
|
||||
:disabled="osc.isApplying.value || osc.isCapturing.value">
|
||||
重置
|
||||
</button>
|
||||
<button class="btn btn-outline" @click="osc.refreshRAM" :disabled="osc.isApplying.value || osc.isCapturing.value">
|
||||
刷新RAM
|
||||
</button>
|
||||
<!-- <button class="btn btn-accent" @click="osc.generateTestData" :disabled="osc.isOperationInProgress.value">
|
||||
生成测试数据
|
||||
</button> -->
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 控制面板 -->
|
||||
<div class="control-panel xl:col-span-1">
|
||||
<div class="space-y-6">
|
||||
<!-- 触发设置 -->
|
||||
<div
|
||||
class="card bg-white/80 dark:bg-slate-800/80 backdrop-blur-lg shadow-xl border border-white/20"
|
||||
>
|
||||
<div class="card-body p-4">
|
||||
<h3
|
||||
class="text-lg font-semibold text-slate-800 dark:text-slate-200 flex items-center gap-2 mb-4"
|
||||
>
|
||||
<Target class="w-5 h-5 text-red-500" />
|
||||
触发设置
|
||||
</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">触发边沿</span>
|
||||
</label>
|
||||
<select
|
||||
v-model="osc.config.triggerRisingEdge"
|
||||
class="select select-bordered w-full focus:border-blue-500 transition-colors"
|
||||
>
|
||||
<option :value="true">上升沿 ↗</option>
|
||||
<option :value="false">下降沿 ↘</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">触发电平</span>
|
||||
<span class="label-text-alt">{{
|
||||
osc.config.triggerLevel
|
||||
}}</span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="255"
|
||||
step="1"
|
||||
v-model="osc.config.triggerLevel"
|
||||
class="range range-primary [--range-bg:#2b7fff]"
|
||||
/>
|
||||
<div
|
||||
class="range-labels flex justify-between text-xs text-slate-500 mt-1"
|
||||
>
|
||||
<span>0</span>
|
||||
<span>128</span>
|
||||
<span>255</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 时基设置 -->
|
||||
<div
|
||||
class="card bg-white/80 dark:bg-slate-800/80 backdrop-blur-lg shadow-xl border border-white/20"
|
||||
>
|
||||
<div class="card-body p-4">
|
||||
<h3
|
||||
class="text-lg font-semibold text-slate-800 dark:text-slate-200 flex items-center gap-2 mb-4"
|
||||
>
|
||||
<Clock class="w-5 h-5 text-blue-500" />
|
||||
时基控制
|
||||
</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">水平偏移</span>
|
||||
<span class="label-text-alt">{{
|
||||
osc.config.horizontalShift
|
||||
}}</span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="1000"
|
||||
step="1"
|
||||
v-model="osc.config.horizontalShift"
|
||||
class="range range-secondary [--range-bg:#c27aff]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">抽取率</span>
|
||||
<span class="label-text-alt"
|
||||
>{{ osc.config.decimationRate }}%</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
v-model="osc.config.decimationRate"
|
||||
class="range range-accent [--range-bg:#fb64b6]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">刷新间隔</span>
|
||||
<span class="label-text-alt">{{ refreshCycle }}ms</span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="1"
|
||||
max="1000"
|
||||
step="1"
|
||||
v-model="refreshCycle"
|
||||
class="range range-info [--range-bg:#51a2ff]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 系统控制 -->
|
||||
<div
|
||||
class="card bg-white/80 dark:bg-slate-800/80 backdrop-blur-lg shadow-xl border border-white/20"
|
||||
>
|
||||
<div class="card-body p-4">
|
||||
<div
|
||||
class="card-title flex flex-row justify-between items-center mb-4"
|
||||
>
|
||||
<h3
|
||||
class="text-lg font-semibold text-slate-800 dark:text-slate-200 flex items-center gap-2"
|
||||
>
|
||||
<Settings class="w-5 h-5 text-purple-500" />
|
||||
系统控制
|
||||
</h3>
|
||||
|
||||
<!-- 自动应用开关 -->
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer">
|
||||
<span class="label-text text-sm font-medium"
|
||||
>自动应用设置</span
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
v-model="osc.isAutoApplying"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- 控制按钮组 -->
|
||||
<div class="space-y-2">
|
||||
<button
|
||||
class="btn-primary-full"
|
||||
@click="applyConfiguration"
|
||||
:disabled="osc.isApplying.value || osc.isCapturing.value"
|
||||
>
|
||||
<CheckCircle class="w-4 h-4" />
|
||||
应用配置
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn-secondary-full"
|
||||
@click="resetConfiguration"
|
||||
:disabled="osc.isApplying.value || osc.isCapturing.value"
|
||||
>
|
||||
<RotateCcw class="w-4 h-4" />
|
||||
重置配置
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn-outline-full"
|
||||
@click="osc.refreshRAM"
|
||||
:disabled="osc.isApplying.value || osc.isCapturing.value"
|
||||
>
|
||||
<RefreshCw class="w-4 h-4" />
|
||||
刷新RAM
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态提示 -->
|
||||
<div
|
||||
v-if="osc.isApplying.value"
|
||||
class="fixed bottom-4 right-4 alert alert-info shadow-lg max-w-sm animate-slide-in-right"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="animate-spin w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full"
|
||||
></div>
|
||||
<span>正在应用配置...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Activity } from "lucide-vue-next";
|
||||
import {
|
||||
Activity,
|
||||
Settings,
|
||||
Play,
|
||||
Square,
|
||||
Trash2,
|
||||
Zap,
|
||||
Target,
|
||||
Clock,
|
||||
CheckCircle,
|
||||
RotateCcw,
|
||||
RefreshCw,
|
||||
} from "lucide-vue-next";
|
||||
import { OscilloscopeWaveformDisplay } from "@/components/Oscilloscope";
|
||||
import { useEquipments } from "@/stores/equipments";
|
||||
import { useOscilloscopeState } from "@/components/Oscilloscope/OscilloscopeManager";
|
||||
import { useRequiredInjection } from "@/utils/Common";
|
||||
import { ref, computed } from "vue";
|
||||
|
||||
// 使用全局设备配置
|
||||
const equipments = useEquipments();
|
||||
@@ -111,6 +338,178 @@ const equipments = useEquipments();
|
||||
// 获取示波器状态和操作
|
||||
const osc = useRequiredInjection(useOscilloscopeState);
|
||||
|
||||
const refreshCycle = ref(10);
|
||||
|
||||
// 计算是否有波形数据
|
||||
const hasWaveformData = computed(() => {
|
||||
const data = osc.oscData.value;
|
||||
return data && data.x && data.y && data.x.length > 0;
|
||||
});
|
||||
|
||||
// 应用配置
|
||||
const applyConfiguration = () => osc.applyConfiguration();
|
||||
function applyConfiguration() {
|
||||
osc.applyConfiguration();
|
||||
}
|
||||
|
||||
function toggleCapture() {
|
||||
osc.toggleCapture();
|
||||
}
|
||||
|
||||
function resetConfiguration() {
|
||||
osc.resetConfiguration();
|
||||
refreshCycle.value = 1000 / osc.config.captureFrequency;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
@import "@/assets/main.css";
|
||||
/* 渐变按钮样式 */
|
||||
.btn-gradient {
|
||||
@apply px-6 py-3 rounded-lg font-medium transition-all duration-300 transform hover:scale-105 active:scale-95 shadow-lg flex items-center gap-2;
|
||||
}
|
||||
|
||||
.btn-start {
|
||||
@apply bg-gradient-to-r from-green-500 to-blue-600 hover:from-green-600 hover:to-blue-700 text-white shadow-green-200 hover:shadow-green-300;
|
||||
}
|
||||
|
||||
.btn-stop {
|
||||
@apply bg-gradient-to-r from-red-500 to-pink-600 hover:from-red-600 hover:to-pink-700 text-white shadow-red-200 hover:shadow-red-300;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
@apply px-4 py-3 bg-gradient-to-r from-orange-500 to-red-500 hover:from-orange-600 hover:to-red-600 text-white rounded-lg font-medium transition-all duration-300 transform hover:scale-105 active:scale-95 shadow-lg flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none;
|
||||
}
|
||||
|
||||
/* 全宽按钮样式 */
|
||||
.btn-primary-full {
|
||||
@apply w-full px-4 py-3 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white rounded-lg font-medium transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98] shadow-lg flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none;
|
||||
}
|
||||
|
||||
.btn-secondary-full {
|
||||
@apply w-full px-4 py-3 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-700 text-white rounded-lg font-medium transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98] shadow-lg flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none;
|
||||
}
|
||||
|
||||
.btn-outline-full {
|
||||
@apply w-full px-4 py-3 border-2 border-slate-300 dark:border-slate-600 hover:border-blue-500 dark:hover:border-blue-400 text-slate-700 dark:text-slate-300 hover:text-blue-600 dark:hover:text-blue-400 rounded-lg font-medium transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98] shadow-sm hover:shadow-md flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none;
|
||||
}
|
||||
|
||||
/* 滑块样式美化 */
|
||||
.range {
|
||||
@apply rounded-lg appearance-none cursor-pointer;
|
||||
--range-fill: 0;
|
||||
--range-thumb: white;
|
||||
}
|
||||
|
||||
.range::-webkit-slider-thumb {
|
||||
@apply appearance-none bg-white border-2 border-current rounded-full cursor-pointer shadow-lg hover:shadow-xl transition-shadow duration-200;
|
||||
}
|
||||
|
||||
.range::-moz-range-thumb {
|
||||
@apply bg-white border-2 border-current rounded-full cursor-pointer shadow-lg hover:shadow-xl transition-shadow duration-200;
|
||||
}
|
||||
|
||||
/* 范围标签 */
|
||||
.range-labels {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* 卡片悬停效果 */
|
||||
.card {
|
||||
@apply transition-all duration-300 hover:shadow-2xl hover:scale-[1.01];
|
||||
}
|
||||
|
||||
/* 自定义动画 */
|
||||
@keyframes slide-in-right {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-slide-in-right {
|
||||
animation: slide-in-right 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* 玻璃态效果增强 */
|
||||
.backdrop-blur-lg {
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
/* 状态指示器脉动效果 */
|
||||
@keyframes pulse-glow {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 5px currentColor;
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0 0 20px currentColor,
|
||||
0 0 30px currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
.status-indicator .animate-pulse {
|
||||
animation: pulse-glow 2s infinite;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 1280px) {
|
||||
.main-content {
|
||||
@apply grid-cols-1;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
@apply order-first;
|
||||
}
|
||||
|
||||
.control-panel .space-y-6 {
|
||||
@apply grid grid-cols-1 md:grid-cols-3 gap-4 space-y-0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.control-panel .space-y-6 {
|
||||
@apply grid-cols-1 space-y-4;
|
||||
}
|
||||
|
||||
.control-buttons {
|
||||
@apply flex-col gap-2;
|
||||
}
|
||||
|
||||
.status-bar .card-body {
|
||||
@apply flex-col items-start gap-4;
|
||||
}
|
||||
}
|
||||
|
||||
/* 滚动条美化 */
|
||||
::-webkit-scrollbar {
|
||||
@apply w-2;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
@apply bg-slate-100 dark:bg-slate-800 rounded-full;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
@apply bg-slate-300 dark:bg-slate-600 rounded-full hover:bg-slate-400 dark:hover:bg-slate-500;
|
||||
}
|
||||
|
||||
/* 输入焦点效果 */
|
||||
.select:focus,
|
||||
.input:focus {
|
||||
@apply ring-2 ring-blue-500 opacity-50 border-blue-500;
|
||||
}
|
||||
|
||||
/* 切换开关样式 */
|
||||
.toggle {
|
||||
@apply transition-all duration-300;
|
||||
}
|
||||
|
||||
.toggle:checked {
|
||||
@apply shadow-lg;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user