feat: update toggle components and enhance chatbot layout; upgrade dependencies and improve UI structure

This commit is contained in:
吳元皓 2025-05-13 09:57:48 +08:00
parent 5bf857f3cd
commit 28240b38dc
9 changed files with 212 additions and 29 deletions

View File

@ -696,13 +696,13 @@
"@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0" } }, "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ=="], "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.32.1", "", { "dependencies": { "@typescript-eslint/types": "8.32.1", "@typescript-eslint/visitor-keys": "8.32.1" } }, "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.32.0", "", {}, "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA=="], "@typescript-eslint/types": ["@typescript-eslint/types@8.32.1", "", {}, "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ=="], "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.32.1", "", { "dependencies": { "@typescript-eslint/types": "8.32.1", "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w=="], "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.32.1", "", { "dependencies": { "@typescript-eslint/types": "8.32.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w=="],
"@unhead/addons": ["@unhead/addons@2.0.8", "", { "dependencies": { "@rollup/pluginutils": "^5.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17", "mlly": "^1.7.4", "ufo": "^1.6.1", "unplugin": "^2.3.2", "unplugin-ast": "^0.14.6" } }, "sha512-FnFBo10ot3flopxgZYUjnJ+r4voZ7/wiPaOod5evShy/3NtC4aIZdma4JLcpt+HtBs9l4zH4SVneYWFrTRXVtg=="], "@unhead/addons": ["@unhead/addons@2.0.8", "", { "dependencies": { "@rollup/pluginutils": "^5.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17", "mlly": "^1.7.4", "ufo": "^1.6.1", "unplugin": "^2.3.2", "unplugin-ast": "^0.14.6" } }, "sha512-FnFBo10ot3flopxgZYUjnJ+r4voZ7/wiPaOod5evShy/3NtC4aIZdma4JLcpt+HtBs9l4zH4SVneYWFrTRXVtg=="],
@ -1128,7 +1128,7 @@
"effect": ["effect@3.14.21", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-TKR7zfWcuZgEdWd+oIGA8LdREj/c+1Q0wz4pWqQtYT7VHnkW/QQEYCXgrDI5dT6lJgRTgyQAC1bAnpAf6MdjIA=="], "effect": ["effect@3.14.21", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-TKR7zfWcuZgEdWd+oIGA8LdREj/c+1Q0wz4pWqQtYT7VHnkW/QQEYCXgrDI5dT6lJgRTgyQAC1bAnpAf6MdjIA=="],
"electron-to-chromium": ["electron-to-chromium@1.5.151", "", {}, "sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA=="], "electron-to-chromium": ["electron-to-chromium@1.5.152", "", {}, "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg=="],
"emoji-datasource": ["emoji-datasource@15.0.1", "", {}, "sha512-aF5Q6LCKXzJzpG4K0ETiItuzz0xLYxNexR9qWw45/shuuEDWZkOIbeGHA23uopOSYA/LmeZIXIFsySCx+YKg2g=="], "emoji-datasource": ["emoji-datasource@15.0.1", "", {}, "sha512-aF5Q6LCKXzJzpG4K0ETiItuzz0xLYxNexR9qWw45/shuuEDWZkOIbeGHA23uopOSYA/LmeZIXIFsySCx+YKg2g=="],
@ -1830,7 +1830,7 @@
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
"pg-protocol": ["pg-protocol@1.9.5", "", {}, "sha512-DYTWtWpfd5FOro3UnAfwvhD8jh59r2ig8bPtc9H8Ds7MscE/9NYruUQWFAOuraRl29jwcT2kyMFQ3MxeaVjUhg=="], "pg-protocol": ["pg-protocol@1.10.0", "", {}, "sha512-IpdytjudNuLv8nhlHs/UrVBhU0e78J0oIS/0AVdTbWxSOkFUVdsHC/NrorO6nXsQNDTT1kzDSOMJubBQviX18Q=="],
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
@ -2050,7 +2050,7 @@
"scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="], "scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="],
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
@ -2250,7 +2250,7 @@
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"unenv": ["unenv@2.0.0-rc.15", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.5.4" } }, "sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA=="], "unenv": ["unenv@2.0.0-rc.17", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="],
"unhead": ["unhead@2.0.8", "", { "dependencies": { "hookable": "^5.5.3" } }, "sha512-63WR+y08RZE7ChiFdgNY64haAkhCtUS5/HM7xo4Q83NA63txWbEh2WGmrKbArdQmSct+XlqbFN8ZL1yWpQEHEA=="], "unhead": ["unhead@2.0.8", "", { "dependencies": { "hookable": "^5.5.3" } }, "sha512-63WR+y08RZE7ChiFdgNY64haAkhCtUS5/HM7xo4Q83NA63txWbEh2WGmrKbArdQmSct+XlqbFN8ZL1yWpQEHEA=="],

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { History, Plus } from "lucide-vue-next";
const { t } = useI18n(); const { t } = useI18n();
const cookie = useCookie("lastChatId"); const cookie = useCookie("lastChatId");
const lastChatId = cookie.value; const lastChatId = cookie.value;
@ -9,5 +10,20 @@ onMounted(() => {
}); });
</script> </script>
<template> <template>
<div class="justify-center align-center text-center flex flex-col">Hi</div> <div class="justify-center align-center text-center flex flex-col">
<div class="flex flex-row justify-between">
<div>Chat Name</div>
<div class="flex flex-row justify-center align-center text-center">
<div class="flex flex-row justify-center align-center text-center gap-2">
<button class="p-2 rounded-lg hover:bg-gray-300">
<History class="h-4 w-4" />
</button>
<button class="p-2 rounded-lg hover:bg-gray-300">
<Plus class="h-4 w-4" />
</button>
</div>
</div>
</div>
<hr/>
</div>
</template> </template>

View File

@ -0,0 +1,44 @@
<script setup lang="ts">
import type { toggleVariants } from "@/components/ui/toggle";
import type { VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import {
ToggleGroupRoot,
type ToggleGroupRootEmits,
type ToggleGroupRootProps,
useForwardPropsEmits,
} from "reka-ui";
import { computed, type HTMLAttributes, provide } from "vue";
type ToggleGroupVariants = VariantProps<typeof toggleVariants>;
const props = defineProps<
ToggleGroupRootProps & {
class?: HTMLAttributes["class"];
variant?: ToggleGroupVariants["variant"];
size?: ToggleGroupVariants["size"];
}
>();
const emits = defineEmits<ToggleGroupRootEmits>();
provide("toggleGroup", {
variant: props.variant,
size: props.size,
});
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<ToggleGroupRoot
v-bind="forwarded"
:class="cn('flex items-center justify-center gap-1', props.class)"
>
<slot />
</ToggleGroupRoot>
</template>

View File

@ -0,0 +1,47 @@
<script setup lang="ts">
import type { VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { toggleVariants } from "@/components/ui/toggle";
import {
ToggleGroupItem,
type ToggleGroupItemProps,
useForwardProps,
} from "reka-ui";
import { computed, type HTMLAttributes, inject } from "vue";
type ToggleGroupVariants = VariantProps<typeof toggleVariants>;
const props = defineProps<
ToggleGroupItemProps & {
class?: HTMLAttributes["class"];
variant?: ToggleGroupVariants["variant"];
size?: ToggleGroupVariants["size"];
}
>();
const context = inject<ToggleGroupVariants>("toggleGroup");
const delegatedProps = computed(() => {
const { class: _, variant, size, ...delegated } = props;
return delegated;
});
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<ToggleGroupItem
v-bind="forwardedProps"
:class="
cn(
toggleVariants({
variant: context?.variant || variant,
size: context?.size || size,
}),
props.class,
)
"
>
<slot />
</ToggleGroupItem>
</template>

View File

@ -0,0 +1,2 @@
export { default as ToggleGroup } from "./ToggleGroup.vue";
export { default as ToggleGroupItem } from "./ToggleGroupItem.vue";

View File

@ -0,0 +1,45 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import {
Toggle,
type ToggleEmits,
type ToggleProps,
useForwardPropsEmits,
} from "reka-ui";
import { computed, type HTMLAttributes } from "vue";
import { type ToggleVariants, toggleVariants } from ".";
const props = withDefaults(
defineProps<
ToggleProps & {
class?: HTMLAttributes["class"];
variant?: ToggleVariants["variant"];
size?: ToggleVariants["size"];
}
>(),
{
variant: "default",
size: "default",
disabled: false,
},
);
const emits = defineEmits<ToggleEmits>();
const delegatedProps = computed(() => {
const { class: _, size, variant, ...delegated } = props;
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<Toggle
v-bind="forwarded"
:class="cn(toggleVariants({ variant, size }), props.class)"
>
<slot />
</Toggle>
</template>

View File

@ -0,0 +1,27 @@
import { cva, type VariantProps } from "class-variance-authority";
export { default as Toggle } from "./Toggle.vue";
export const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-2 min-w-9",
sm: "h-8 px-1.5 min-w-8",
lg: "h-10 px-2.5 min-w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
export type ToggleVariants = VariantProps<typeof toggleVariants>;

View File

@ -288,7 +288,7 @@ watchEffect((cleanupFn) => {
<template> <template>
<div v-if="bootingAnimation"> <div v-if="bootingAnimation">
<div <div
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-0" class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-0 overscroll-none"
> >
<Progress <Progress
v-model="progress" v-model="progress"
@ -301,7 +301,7 @@ watchEffect((cleanupFn) => {
</div> </div>
</div> </div>
<div <div
class="absolute inset-x-0 flex flex-row px-2 py-1 bg-[#7D7C7C]/70 text-white justify-between align-center text-center z-50" class="absolute inset-x-0 flex flex-row px-2 py-1 bg-[#7D7C7C]/70 text-white justify-between align-center text-center z-50 overscroll-none"
v-else v-else
> >
<!--Menu container--> <!--Menu container-->

View File

@ -117,26 +117,28 @@ onMounted(() => {
</div> </div>
<br /> <br />
<div class="justify-center align-center text-center w-full flex"> <div class="justify-center align-center text-center w-full flex">
<div class="bg-[#C9C9C9]/60 rounded-xl shadow-lg p-4 m-4 w-1/2 align-center justify-center text-center"> <div
<span class="text-2xl font-bold">Q/A</span> class="bg-[#C9C9C9]/60 rounded-xl shadow-lg p-4 m-4 w-1/2 align-center justify-center text-center"
<Accordion
type="single"
class="align-center justify-center m-auto"
collapsible
:default-value="defaultValue"
> >
<AccordionItem <span class="text-2xl font-bold">Q/A</span>
v-for="item in accordionItems" <Accordion
:key="item.value" type="single"
:value="item.value" class="align-center justify-center m-auto"
collapsible
:default-value="defaultValue"
> >
<AccordionTrigger>{{ item.title }}</AccordionTrigger> <AccordionItem
<AccordionContent> v-for="item in accordionItems"
{{ item.content }} :key="item.value"
</AccordionContent> :value="item.value"
</AccordionItem> >
</Accordion> <AccordionTrigger>{{ item.title }}</AccordionTrigger>
<AccordionContent>
{{ item.content }}
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</div> </div>
</div> </div>
</div>
</template> </template>