mirror of
https://github.com/certd/certd.git
synced 2026-05-17 22:07:34 +08:00
🔱: [client] sync upgrade with 7 commits [trident-sync]
chore: Merge branch 'vben' # Conflicts: # package.json perf: antdv示例改成使用vben框架 chore: vben chore: vben chore: vben
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export { default as ThemeToggle } from './theme-toggle.vue';
|
||||
@@ -0,0 +1,157 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick } from "vue";
|
||||
|
||||
import { VbenButton } from "/@/vben//shadcn-ui";
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
type?: "icon" | "normal";
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: "ThemeToggleButton"
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: "normal"
|
||||
});
|
||||
|
||||
const isDark = defineModel<boolean>();
|
||||
|
||||
const theme = computed(() => {
|
||||
return isDark.value ? "light" : "dark";
|
||||
});
|
||||
|
||||
const bindProps = computed(() => {
|
||||
const type = props.type;
|
||||
|
||||
return type === "normal"
|
||||
? {
|
||||
variant: "heavy" as const
|
||||
}
|
||||
: {
|
||||
class: "rounded-full",
|
||||
size: "icon" as const,
|
||||
style: { padding: "7px" },
|
||||
variant: "icon" as const
|
||||
};
|
||||
});
|
||||
|
||||
function toggleTheme(event: MouseEvent) {
|
||||
const isAppearanceTransition =
|
||||
// @ts-expect-error
|
||||
document.startViewTransition && !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
if (!isAppearanceTransition || !event) {
|
||||
isDark.value = !isDark.value;
|
||||
return;
|
||||
}
|
||||
const x = event.clientX;
|
||||
const y = event.clientY;
|
||||
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
|
||||
// @ts-ignore startViewTransition
|
||||
const transition = document.startViewTransition(async () => {
|
||||
isDark.value = !isDark.value;
|
||||
await nextTick();
|
||||
});
|
||||
transition.ready.then(() => {
|
||||
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];
|
||||
document.documentElement.animate(
|
||||
{
|
||||
clipPath: isDark.value ? [...clipPath].reverse() : clipPath
|
||||
},
|
||||
{
|
||||
duration: 450,
|
||||
easing: "ease-in",
|
||||
pseudoElement: isDark.value ? "::view-transition-old(root)" : "::view-transition-new(root)"
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VbenButton :aria-label="theme" :class="[`is-${theme}`]" aria-live="polite" class="theme-toggle cursor-pointer border-none bg-none" v-bind="bindProps" @click.stop="toggleTheme">
|
||||
<svg aria-hidden="true" height="24" viewBox="0 0 24 24" width="24">
|
||||
<mask id="theme-toggle-moon" class="theme-toggle__moon" fill="hsl(var(--foreground)/80%)" stroke="none">
|
||||
<rect fill="white" height="100%" width="100%" x="0" y="0" />
|
||||
<circle cx="40" cy="8" fill="black" r="11" />
|
||||
</mask>
|
||||
<circle id="sun" class="theme-toggle__sun" cx="12" cy="12" mask="url(#theme-toggle-moon)" r="11" />
|
||||
<g class="theme-toggle__sun-beams">
|
||||
<line x1="12" x2="12" y1="1" y2="3" />
|
||||
<line x1="12" x2="12" y1="21" y2="23" />
|
||||
<line x1="4.22" x2="5.64" y1="4.22" y2="5.64" />
|
||||
<line x1="18.36" x2="19.78" y1="18.36" y2="19.78" />
|
||||
<line x1="1" x2="3" y1="12" y2="12" />
|
||||
<line x1="21" x2="23" y1="12" y2="12" />
|
||||
<line x1="4.22" x2="5.64" y1="19.78" y2="18.36" />
|
||||
<line x1="18.36" x2="19.78" y1="5.64" y2="4.22" />
|
||||
</g>
|
||||
</svg>
|
||||
</VbenButton>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.theme-toggle {
|
||||
&__moon {
|
||||
& > circle {
|
||||
transition: transform 0.5s cubic-bezier(0, 0, 0.3, 1);
|
||||
}
|
||||
}
|
||||
|
||||
&__sun {
|
||||
@apply fill-foreground/90 stroke-none;
|
||||
|
||||
transition: transform 1.6s cubic-bezier(0.25, 0, 0.2, 1);
|
||||
transform-origin: center center;
|
||||
|
||||
&:hover > svg > & {
|
||||
@apply fill-foreground/90;
|
||||
}
|
||||
}
|
||||
|
||||
&__sun-beams {
|
||||
@apply stroke-foreground/90 stroke-[2px];
|
||||
|
||||
transition:
|
||||
transform 1.6s cubic-bezier(0.5, 1.5, 0.75, 1.25),
|
||||
opacity 0.6s cubic-bezier(0.25, 0, 0.3, 1);
|
||||
transform-origin: center center;
|
||||
|
||||
&:hover > svg > & {
|
||||
@apply stroke-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-light {
|
||||
.theme-toggle__sun {
|
||||
@apply scale-50;
|
||||
}
|
||||
|
||||
.theme-toggle__sun-beams {
|
||||
transform: rotateZ(0.25turn);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-dark {
|
||||
.theme-toggle__moon {
|
||||
& > circle {
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
.theme-toggle__sun-beams {
|
||||
@apply opacity-0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover > svg {
|
||||
.theme-toggle__sun,
|
||||
.theme-toggle__moon {
|
||||
@apply fill-foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ThemeModeType } from "/@/vben/types";
|
||||
|
||||
import { MoonStar, Sun, SunMoon } from "/@/vben/icons";
|
||||
import { $t } from "/@/vben/locales";
|
||||
import { preferences, updatePreferences, usePreferences } from "/@/vben/preferences";
|
||||
|
||||
import { ToggleGroup, ToggleGroupItem, VbenTooltip } from "/@/vben//shadcn-ui";
|
||||
|
||||
import ThemeButton from "./theme-button.vue";
|
||||
|
||||
defineOptions({
|
||||
name: "ThemeToggle"
|
||||
});
|
||||
|
||||
withDefaults(defineProps<{ shouldOnHover?: boolean }>(), {
|
||||
shouldOnHover: false
|
||||
});
|
||||
|
||||
function handleChange(isDark: boolean) {
|
||||
updatePreferences({
|
||||
theme: { mode: isDark ? "dark" : "light" }
|
||||
});
|
||||
}
|
||||
|
||||
const { isDark } = usePreferences();
|
||||
|
||||
const PRESETS = [
|
||||
{
|
||||
icon: Sun,
|
||||
name: "light",
|
||||
title: $t("preferences.theme.light")
|
||||
},
|
||||
{
|
||||
icon: MoonStar,
|
||||
name: "dark",
|
||||
title: $t("preferences.theme.dark")
|
||||
},
|
||||
{
|
||||
icon: SunMoon,
|
||||
name: "auto",
|
||||
title: $t("preferences.followSystem")
|
||||
}
|
||||
];
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VbenTooltip :disabled="!shouldOnHover" side="bottom">
|
||||
<template #trigger>
|
||||
<ThemeButton :model-value="isDark" type="icon" @update:model-value="handleChange" />
|
||||
</template>
|
||||
<ToggleGroup :model-value="preferences.theme.mode" class="gap-2" type="single" variant="outline" @update:model-value="(val) => updatePreferences({ theme: { mode: val as ThemeModeType } })">
|
||||
<ToggleGroupItem v-for="item in PRESETS" :key="item.name" :value="item.name">
|
||||
<component :is="item.icon" class="size-5" />
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</VbenTooltip>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user