feat: Refactor icon components to support filled and outlined states

- Updated Add.vue to handle filled and outlined states, merging AddFilled.vue functionality.
- Refactored Bell.vue and BellFilled.vue into a single component with filled state support.
- Created Credit.vue for credit card icon with filled and outlined states.
- Refactored Home.vue and HomeFilled.vue into a single component with filled state support.
- Refactored Layout.vue and LayoutFilled.vue into a single component with filled state support.
- Refactored Upload.vue and UploadFilled.vue into a single component with filled state support.
- Refactored Video.vue and VideoFilled.vue into a single component with filled state support.
- Enhanced index.tsx to include nonce for security in SSR.
- Updated main.ts to handle application data from SSR.
- Improved auth layout to include meta description for SEO.
- Updated routes to include meta information for head management.
- Simplified auth store methods for better readability and error handling.
- Updated UnoCSS configuration to include class prefix for better utility management.
This commit is contained in:
2026-01-05 18:27:35 +07:00
parent 61509b794b
commit a6f5ba8c90
23 changed files with 190 additions and 100 deletions

2
components.d.ts vendored
View File

@@ -19,6 +19,7 @@ declare module 'vue' {
Button: typeof import('primevue/button')['default']
Checkbox: typeof import('primevue/checkbox')['default']
CheckIcon: typeof import('./src/components/icons/CheckIcon.vue')['default']
Credit: typeof import('./src/components/icons/Credit.vue')['default']
DashboardLayout: typeof import('./src/components/DashboardLayout.vue')['default']
Home: typeof import('./src/components/icons/Home.vue')['default']
HomeFilled: typeof import('./src/components/icons/HomeFilled.vue')['default']
@@ -48,6 +49,7 @@ declare global {
const Button: typeof import('primevue/button')['default']
const Checkbox: typeof import('primevue/checkbox')['default']
const CheckIcon: typeof import('./src/components/icons/CheckIcon.vue')['default']
const Credit: typeof import('./src/components/icons/Credit.vue')['default']
const DashboardLayout: typeof import('./src/components/DashboardLayout.vue')['default']
const Home: typeof import('./src/components/icons/Home.vue')['default']
const HomeFilled: typeof import('./src/components/icons/HomeFilled.vue')['default']

View File

@@ -224,11 +224,11 @@ async function getCSRFToken() {
const payload = await verify(token, JWT_SECRET) as any;
const stored = csrfTokens.get(payload.sessionId);
if (!stored) {
throw new Error('CSRF token not found');
}
// if (!stored) {
// throw new Error('CSRF token not found');
// }
return { csrfToken: stored.token };
return { csrfToken: stored?.token || null };
}
export const authMethods = {

View File

@@ -6,7 +6,7 @@ import {
import { tinyassert } from "@hiogawa/utils";
import { MiddlewareHandler, type Context, type Next } from "hono";
import { getContext } from "hono/context-storage";
import { register } from "module";
import { csrf } from 'hono/csrf'
import { z } from "zod";
import { authMethods } from "./auth";
import { jwt } from "hono/jwt";
@@ -320,7 +320,9 @@ export const rpcServer = async (c: Context, next: Next) => {
if (c.req.path !== endpoint && !c.req.path.startsWith(endpoint + "/")) {
return await next();
}
// c.get("redis").has(`auth_token:${}`)
const cert = c.req.header()
console.log("RPC Request Path:", c.req.raw.cf);
// if (!cert) return c.text('Forbidden', 403)
const handler = exposeTinyRpc({
routes,
adapter: httpServerAdapter({ endpoint }),

View File

@@ -1,37 +1,36 @@
<script lang="ts" setup>
import Add from "@/components/icons/Add.vue";
import AddFilled from "@/components/icons/AddFilled.vue";
import Bell from "@/components/icons/Bell.vue";
import BellFilled from "@/components/icons/BellFilled.vue";
import Home from "@/components/icons/Home.vue";
import HomeFilled from "@/components/icons/HomeFilled.vue";
import Video from "@/components/icons/Video.vue";
import VideoFilled from "@/components/icons/VideoFilled.vue";
import Credit from "@/components/icons/Credit.vue";
import Upload from "./icons/Upload.vue";
import { cn } from "@/lib/utils";
import { useAuthStore } from "@/stores/auth";
import { createStaticVNode } from "vue";
import Upload from "./icons/Upload.vue";
import UploadFilled from "./icons/UploadFilled.vue";
const auth = useAuthStore();
const className = ":uno: w-12 h-12 p-2 rounded-2xl hover:bg-primary/10 flex press-animated items-center justify-center";
const className = ":uno: w-12 h-12 p-2 rounded-2xl hover:bg-primary/15 flex press-animated items-center justify-center";
const homeHoist = createStaticVNode(`<img class="h-8 w-8" src="/apple-touch-icon.png" alt="Logo" />`, 1);
const links = [
{ href: "/fdsfsd", label: "app", icon: homeHoist, exact: homeHoist, type: "btn" },
{ href: "/", label: "Home", icon: Home, exact: HomeFilled, type: "a" },
{ href: "/upload", label: "Upload", icon: Upload, exact: UploadFilled, type: "a" },
{ href: "/video", label: "Video", icon: Video, exact: VideoFilled, type: "a" },
{ href: "/add", label: "Add", icon: Add, exact: AddFilled, type: "a" },
{ href: "/notification", label: "Notification", icon: Bell, exact: BellFilled, type: "a" },
{ href: "/fdsfsd", label: "app", icon: homeHoist, type: "btn" },
{ href: "/", label: "Home", icon: Home, type: "a" },
{ href: "/upload", label: "Upload", icon: Upload, type: "a" },
{ href: "/video", label: "Video", icon: Video, type: "a" },
{ href: "/plans", label: "Plans", icon: Credit, type: "a" },
{ href: "/notification", label: "Notification", icon: Bell, type: "a" },
];
</script>
<template>
<header class="fixed left-0 w-18 flex flex-col items-center pt-4 gap-6 z-41 max-h-screen h-screen border-r border-gray-200">
<component :is="i.type === 'a' ? 'router-link' : 'div'" v-for="i in links" :key="i.label" v-bind="i.type === 'a' ? { to: i.href } : {}" v-tooltip="i.label" :class="cn(className, $route.path === i.href && 'bg-primary/10')">
<component :is="$route.path === i.href ? i.exact : i.icon" />
<header
class=":uno: fixed left-0 w-18 flex flex-col items-center pt-4 gap-6 z-41 max-h-screen h-screen border-r border-gray-200 bg-white">
<component :is="i.type === 'a' ? 'router-link' : 'div'" v-for="i in links" :key="i.label"
v-bind="i.type === 'a' ? { to: i.href } : {}" v-tooltip="i.label"
:class="cn(className, $route.path === i.href && 'bg-primary/15')">
<component :is="i.icon" :filled="$route.path === i.href" />
</component>
<div class="w-12 h-12 rounded-2xl hover:bg-primary/10 flex">
<div class="w-12 h-12 rounded-2xl hover:bg-primary/15 flex">
<button class="h-[38px] w-[38px] rounded-full m-a ring-2 ring flex press-animated" @click="auth.logout()">
<img class="h-8 w-8 rounded-full m-a ring-1 ring-white"
src="https://picsum.photos/seed/user123/40/40.jpg" alt="User avatar" />

View File

@@ -1,7 +1,19 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" viewBox="-10 -226 468 468">
<svg v-if="filled" aria-hidden="true" aria-label="" class="v-mid m-a" height="24" role="img" viewBox="0 0 468 468"
width="24">
<path
d="M42 74v320c0 18 14 32 32 32h320c18 0 32-14 32-32V74c0-18-14-32-32-32H74c-18 0-32 14-32 32zm80 160c0-9 7-16 16-16h80v-80c0-9 7-16 16-16s16 7 16 16v80h80c9 0 16 7 16 16s-7 16-16 16h-80v80c0 9-7 16-16 16s-16-7-16-16v-80h-80c-9 0-16-7-16-16z"
fill="#a6acb9" />
<path
d="M74 42c-18 0-32 14-32 32v320c0 18 14 32 32 32h320c18 0 32-14 32-32V74c0-18-14-32-32-32H74zM10 74c0-35 29-64 64-64h320c35 0 64 29 64 64v320c0 35-29 64-64 64H74c-35 0-64-29-64-64V74zm208 256v-80h-80c-9 0-16-7-16-16s7-16 16-16h80v-80c0-9 7-16 16-16s16 7 16 16v80h80c9 0 16 7 16 16s-7 16-16 16h-80v80c0 9-7 16-16 16s-16-7-16-16z"
fill="#1e3050" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" viewBox="-10 -226 468 468">
<path
d="M64-184c-18 0-32 14-32 32v320c0 18 14 32 32 32h320c18 0 32-14 32-32v-320c0-18-14-32-32-32H64zM0-152c0-35 29-64 64-64h320c35 0 64 29 64 64v320c0 35-29 64-64 64H64c-35 0-64-29-64-64v-320zm208 256V24h-80c-9 0-16-7-16-16s7-16 16-16h80v-80c0-9 7-16 16-16s16 7 16 16v80h80c9 0 16 7 16 16s-7 16-16 16h-80v80c0 9-7 16-16 16s-16-7-16-16z"
fill="#1e3050" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,10 +0,0 @@
<template>
<svg aria-hidden="true" aria-label="" class="v-mid m-a" height="24" role="img" viewBox="0 0 468 468" width="24">
<path
d="M42 74v320c0 18 14 32 32 32h320c18 0 32-14 32-32V74c0-18-14-32-32-32H74c-18 0-32 14-32 32zm80 160c0-9 7-16 16-16h80v-80c0-9 7-16 16-16s16 7 16 16v80h80c9 0 16 7 16 16s-7 16-16 16h-80v80c0 9-7 16-16 16s-16-7-16-16v-80h-80c-9 0-16-7-16-16z"
fill="#a6acb9" />
<path
d="M74 42c-18 0-32 14-32 32v320c0 18 14 32 32 32h320c18 0 32-14 32-32V74c0-18-14-32-32-32H74zM10 74c0-35 29-64 64-64h320c35 0 64 29 64 64v320c0 35-29 64-64 64H74c-35 0-64-29-64-64V74zm208 256v-80h-80c-9 0-16-7-16-16s7-16 16-16h80v-80c0-9 7-16 16-16s16 7 16 16v80h80c9 0 16 7 16 16s-7 16-16 16h-80v80c0 9-7 16-16 16s-16-7-16-16z"
fill="#1e3050" />
</svg>
</template>

View File

@@ -1,3 +1,18 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" viewBox="-10 -258 468 532"><path d="M224-248c-13 0-24 11-24 24v10C119-203 56-133 56-48v15C56 4 46 41 27 74L5 111c-3 6-5 13-5 19 0 21 17 38 38 38h372c21 0 38-17 38-38 0-6-2-13-5-19l-22-37c-19-33-29-70-29-108v-14c0-85-63-155-144-166v-10c0-13-11-24-24-24zm168 368H56l12-22c24-40 36-85 36-131v-15c0-66 54-120 120-120s120 54 120 120v15c0 46 12 91 36 131l12 22zm-236 96c10 28 37 48 68 48s58-20 68-48H156z" fill="#1e3050"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" v-if="filled" height="24" width="24" viewBox="0 0 468 532">
<path
d="M66 378h337l-13-22c-24-40-36-85-36-131v-15c0-66-54-120-120-120s-120 54-120 120v15c0 46-12 91-35 131l-13 22z"
fill="#a6acb9" />
<path
d="M234 10c-13 0-24 11-24 24v10C129 55 66 125 66 210v15c0 37-10 74-29 107l-22 37c-3 6-5 13-5 19 0 21 17 38 38 38h372c21 0 38-17 38-38 0-6-2-13-5-19l-22-37c-19-33-29-70-29-108v-14c0-85-63-155-144-166V34c0-13-11-24-24-24zm168 368H66l12-22c24-40 36-85 36-131v-15c0-66 54-120 120-120s120 54 120 120v15c0 46 12 91 36 131l12 22zm-236 96c10 28 37 48 68 48s58-20 68-48H166z"
fill="#1e3050" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" v-else height="24" viewBox="-10 -258 468 532">
<path
d="M224-248c-13 0-24 11-24 24v10C119-203 56-133 56-48v15C56 4 46 41 27 74L5 111c-3 6-5 13-5 19 0 21 17 38 38 38h372c21 0 38-17 38-38 0-6-2-13-5-19l-22-37c-19-33-29-70-29-108v-14c0-85-63-155-144-166v-10c0-13-11-24-24-24zm168 368H56l12-22c24-40 36-85 36-131v-15c0-66 54-120 120-120s120 54 120 120v15c0 46 12 91 36 131l12 22zm-236 96c10 28 37 48 68 48s58-20 68-48H156z"
fill="#1e3050" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,3 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" width="24" viewBox="0 0 468 532"><path d="M66 378h337l-13-22c-24-40-36-85-36-131v-15c0-66-54-120-120-120s-120 54-120 120v15c0 46-12 91-35 131l-13 22z" fill="#a6acb9"/><path d="M234 10c-13 0-24 11-24 24v10C129 55 66 125 66 210v15c0 37-10 74-29 107l-22 37c-3 6-5 13-5 19 0 21 17 38 38 38h372c21 0 38-17 38-38 0-6-2-13-5-19l-22-37c-19-33-29-70-29-108v-14c0-85-63-155-144-166V34c0-13-11-24-24-24zm168 368H66l12-22c24-40 36-85 36-131v-15c0-66 54-120 120-120s120 54 120 120v15c0 46 12 91 36 131l12 22zm-236 96c10 28 37 48 68 48s58-20 68-48H166z" fill="#1e3050"/></svg>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" v-if="filled" width="24" viewBox="0 0 532 404"><path d="M10 74c0-35 29-64 64-64h384c35 0 64 29 64 64v32H10V74zm0 96h512v160c0 35-29 64-64 64H74c-35 0-64-29-64-64V170zm64 136c0 13 11 24 24 24h48c13 0 24-11 24-24s-11-24-24-24H98c-13 0-24 11-24 24zm144 0c0 13 11 24 24 24h64c13 0 24-11 24-24s-11-24-24-24h-64c-13 0-24 11-24 24z" fill="#a6acb9"/><path d="M10 106h512v64H10zm0 0z" fill="#1e3050"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" v-else width="24" viewBox="-10 -194 532 404"><path d="M448-136c9 0 16 7 16 16v32H48v-32c0-9 7-16 16-16h384zm16 112v160c0 9-7 16-16 16H64c-9 0-16-7-16-16V-24h416zM64-184c-35 0-64 29-64 64v256c0 35 29 64 64 64h384c35 0 64-29 64-64v-256c0-35-29-64-64-64H64zM80 96c0 13 11 24 24 24h48c13 0 24-11 24-24s-11-24-24-24h-48c-13 0-24 11-24 24zm144 0c0 13 11 24 24 24h64c13 0 24-11 24-24s-11-24-24-24h-64c-13 0-24 11-24 24z" fill="#1e3050"/></svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,3 +1,18 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" width="24" viewBox="-11 -259 535 533"><path d="M272-242c-9-8-23-8-32 0L8-34C-2-25-3-10 6 0s24 11 34 2l8-7v205c0 35 29 64 64 64h288c35 0 64-29 64-64V-5l8 7c10 9 25 8 34-2s8-25-2-34L272-242zM416-48v248c0 9-7 16-16 16H112c-9 0-16-7-16-16V-48l160-144L416-48z" fill="#1e3050"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" v-if="filled" class="v-mid m-a" height="24" width="24"
viewBox="0 0 539 535">
<path d="M61 281c2-1 4-3 6-5L269 89l202 187c2 2 4 4 6 5v180c0 35-29 64-64 64H125c-35 0-64-29-64-64V281z"
fill="#a6acb9" />
<path
d="M247 22c13-12 32-12 44 0l224 208c13 12 13 32 1 45s-32 14-45 2L269 89 67 276c-13 12-33 12-45-1s-12-33 1-45L247 22z"
fill="#1e3050" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" v-else class="v-mid m-a" height="24" width="24" viewBox="-11 -259 535 533">
<path
d="M272-242c-9-8-23-8-32 0L8-34C-2-25-3-10 6 0s24 11 34 2l8-7v205c0 35 29 64 64 64h288c35 0 64-29 64-64V-5l8 7c10 9 25 8 34-2s8-25-2-34L272-242zM416-48v248c0 9-7 16-16 16H112c-9 0-16-7-16-16V-48l160-144L416-48z"
fill="#1e3050" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,3 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" width="24" viewBox="0 0 539 535"><path d="M61 281c2-1 4-3 6-5L269 89l202 187c2 2 4 4 6 5v180c0 35-29 64-64 64H125c-35 0-64-29-64-64V281z" fill="#a6acb9"/><path d="M247 22c13-12 32-12 44 0l224 208c13 12 13 32 1 45s-32 14-45 2L269 89 67 276c-13 12-33 12-45-1s-12-33 1-45L247 22z" fill="#1e3050"/></svg>
</template>

View File

@@ -1,3 +1,19 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" width="24" viewBox="-10 -226 468 468"><path d="M384-184c18 0 32 14 32 32v64H32v-64c0-18 14-32 32-32h320zM32 168V-56h96v256H64c-18 0-32-14-32-32zm128 32V-56h256v224c0 18-14 32-32 32H160zM64-216c-35 0-64 29-64 64v320c0 35 29 64 64 64h320c35 0 64-29 64-64v-320c0-35-29-64-64-64H64z" fill="#1e3050"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" v-if="filled" class="v-mid m-a" height="24" width="24"
viewBox="0 0 468 468">
<path
d="M42 74v64h384V74c0-18-14-32-32-32H74c-18 0-32 14-32 32zm0 96v224c0 18 14 32 32 32h64V170H42zm128 0v256h224c18 0 32-14 32-32V170H170z"
fill="#a6acb9" />
<path
d="M394 42c18 0 32 14 32 32v64H42V74c0-18 14-32 32-32h320zM42 394V170h96v256H74c-18 0-32-14-32-32zm128 32V170h256v224c0 18-14 32-32 32H170zM74 10c-35 0-64 29-64 64v320c0 35 29 64 64 64h320c35 0 64-29 64-64V74c0-35-29-64-64-64H74z"
fill="#1e3050" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" v-else class="v-mid m-a" height="24" width="24" viewBox="-10 -226 468 468">
<path
d="M384-184c18 0 32 14 32 32v64H32v-64c0-18 14-32 32-32h320zM32 168V-56h96v256H64c-18 0-32-14-32-32zm128 32V-56h256v224c0 18-14 32-32 32H160zM64-216c-35 0-64 29-64 64v320c0 35 29 64 64 64h320c35 0 64-29 64-64v-320c0-35-29-64-64-64H64z"
fill="#1e3050" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,3 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" class="v-mid m-a" height="24" width="24" viewBox="0 0 468 468"><path d="M42 74v64h384V74c0-18-14-32-32-32H74c-18 0-32 14-32 32zm0 96v224c0 18 14 32 32 32h64V170H42zm128 0v256h224c18 0 32-14 32-32V170H170z" fill="#a6acb9"/><path d="M394 42c18 0 32 14 32 32v64H42V74c0-18 14-32 32-32h320zM42 394V170h96v256H74c-18 0-32-14-32-32zm128 32V170h256v224c0 18-14 32-32 32H170zM74 10c-35 0-64 29-64 64v320c0 35 29 64 64 64h320c35 0 64-29 64-64V74c0-35-29-64-64-64H74z" fill="#1e3050"/></svg>
</template>

View File

@@ -1,3 +1,18 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="28" viewBox="-10 -226 596 468"><path d="M240-216c-88 0-160 72-160 160 0 5 0 10 1 15C33-18 0 31 0 88c0 80 65 144 144 144h304c71 0 128-57 128-128 0-50-28-93-70-114 4-12 6-25 6-38 0-66-54-120-120-120-11 0-23 2-33 5-30-33-72-53-119-53zM128-56c0-62 50-112 112-112 38 0 71 19 91 47 7 10 20 13 30 8 9-4 20-7 31-7 40 0 72 32 72 72 0 14-4 27-11 38-4 7-5 15-2 22s9 13 16 14c35 9 61 41 61 78 0 44-36 80-80 80H144c-53 0-96-43-96-96 0-43 28-79 67-91 11-4 18-16 16-29-2-7-3-16-3-24zm177 7c-9-9-25-9-34 0l-64 64c-9 9-9 25 0 34 10 9 25 9 34 0l23-23v86c0 13 11 24 24 24s24-11 24-24V26l23 23c9 9 25 9 34 0s9-25 0-34l-64-64z" fill="#1e3050"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" v-if="filled" width="28" viewBox="0 0 596 468">
<path
d="M10 314c0-63 41-117 98-136-1-8-2-16-2-24 0-79 65-144 144-144 55 0 104 31 128 77 14-8 30-13 48-13 53 0 96 43 96 96 0 16-4 31-10 44 44 20 74 64 74 116 0 71-57 128-128 128H154c-79 0-144-64-144-144zm199-73c-9 9-9 25 0 34s25 9 34 0l31-31v102c0 13 11 24 24 24s24-11 24-24V244l31 31c9 9 25 9 34 0s9-25 0-34l-72-72c-10-9-25-9-34 0l-72 72z"
fill="#a6acb9" />
<path
d="M281 169c9-9 25-9 34 0l72 72c9 9 9 25 0 34s-25 9-34 0l-31-31v102c0 13-11 24-24 24s-24-11-24-24V244l-31 31c-9 9-25 9-34 0s-9-25 0-34l72-72z"
fill="#1e3050" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" v-else width="28" viewBox="-10 -226 596 468">
<path
d="M240-216c-88 0-160 72-160 160 0 5 0 10 1 15C33-18 0 31 0 88c0 80 65 144 144 144h304c71 0 128-57 128-128 0-50-28-93-70-114 4-12 6-25 6-38 0-66-54-120-120-120-11 0-23 2-33 5-30-33-72-53-119-53zM128-56c0-62 50-112 112-112 38 0 71 19 91 47 7 10 20 13 30 8 9-4 20-7 31-7 40 0 72 32 72 72 0 14-4 27-11 38-4 7-5 15-2 22s9 13 16 14c35 9 61 41 61 78 0 44-36 80-80 80H144c-53 0-96-43-96-96 0-43 28-79 67-91 11-4 18-16 16-29-2-7-3-16-3-24zm177 7c-9-9-25-9-34 0l-64 64c-9 9-9 25 0 34 10 9 25 9 34 0l23-23v86c0 13 11 24 24 24s24-11 24-24V26l23 23c9 9 25 9 34 0s9-25 0-34l-64-64z"
fill="#1e3050" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,3 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="28" viewBox="0 0 596 468"><path d="M10 314c0-63 41-117 98-136-1-8-2-16-2-24 0-79 65-144 144-144 55 0 104 31 128 77 14-8 30-13 48-13 53 0 96 43 96 96 0 16-4 31-10 44 44 20 74 64 74 116 0 71-57 128-128 128H154c-79 0-144-64-144-144zm199-73c-9 9-9 25 0 34s25 9 34 0l31-31v102c0 13 11 24 24 24s24-11 24-24V244l31 31c9 9 25 9 34 0s9-25 0-34l-72-72c-10-9-25-9-34 0l-72 72z" fill="#a6acb9"/><path d="M281 169c9-9 25-9 34 0l72 72c9 9 9 25 0 34s-25 9-34 0l-31-31v102c0 13-11 24-24 24s-24-11-24-24V244l-31 31c-9 9-25 9-34 0s-9-25 0-34l72-72z" fill="#1e3050"/></svg>
</template>

View File

@@ -1,3 +1,16 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="24" viewBox="22 -194 564 404"><path d="M96-136c-9 0-16 7-16 16v256c0 9 7 16 16 16h256c9 0 16-7 16-16v-256c0-9-7-16-16-16H96zm-64 16c0-35 29-64 64-64h256c35 0 64 29 64 64v256c0 35-29 64-64 64H96c-35 0-64-29-64-64v-256zm506-11c4-3 9-5 14-5 13 0 24 11 24 24v240c0 13-11 24-24 24-5 0-10-2-14-5l-74-55V32l64 48V-64l-64 48v-60l74-55z" fill="#1e3050"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" v-if="filled" width="24" viewBox="0 0 532 404">
<path d="M10 74v256c0 35 29 64 64 64h256c35 0 64-29 64-64V74c0-35-29-64-64-64H74c-35 0-64 29-64 64z"
fill="#a6acb9" />
<path d="M394 135v134l90 72c4 3 9 5 14 5 13 0 24-11 24-24V82c0-13-11-24-24-24-5 0-10 2-14 5l-90 72z"
fill="#1e3050" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" v-else width="24" viewBox="22 -194 564 404">
<path
d="M96-136c-9 0-16 7-16 16v256c0 9 7 16 16 16h256c9 0 16-7 16-16v-256c0-9-7-16-16-16H96zm-64 16c0-35 29-64 64-64h256c35 0 64 29 64 64v256c0 35-29 64-64 64H96c-35 0-64-29-64-64v-256zm506-11c4-3 9-5 14-5 13 0 24 11 24 24v240c0 13-11 24-24 24-5 0-10-2-14-5l-74-55V32l64 48V-64l-64 48v-60l74-55z"
fill="#1e3050" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{ class?: string, filled?: boolean }>();
</script>

View File

@@ -1,3 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="24" viewBox="0 0 532 404"><path d="M10 74v256c0 35 29 64 64 64h256c35 0 64-29 64-64V74c0-35-29-64-64-64H74c-35 0-64 29-64 64z" fill="#a6acb9"/><path d="M394 135v134l90 72c4 3 9 5 14 5 13 0 24-11 24-24V82c0-13-11-24-24-24-5 0-10 2-14 5l-90 72z" fill="#1e3050"/></svg>
</template>

View File

@@ -30,6 +30,7 @@ app.get("/.well-known/*", (c) => {
return c.json({ ok: true });
});
app.get("*", async (c) => {
const nonce = crypto.randomUUID();
const url = new URL(c.req.url);
const { app, router, head, pinia, bodyClass } = createApp();
app.provide("honoContext", c);
@@ -59,8 +60,8 @@ app.get("*", async (c) => {
await Promise.all(styleTags.filter(tag => usedStyles.has(tag.name.replace(/-(variables|style)$/, ""))).map(tag => stream.write(`<style type="text/css" data-primevue-style-id="${tag.name}">${tag.value}</style>`)));
await stream.write(`</head><body class='${bodyClass}'>`);
await stream.pipe(appStream);
await stream.write(`<script>window.__SSR_STATE__ = JSON.parse(${htmlEscape(JSON.stringify(JSON.stringify(ctx)))});</script>`);
await stream.write(`<script>window.__PINIA_STATE__ = JSON.parse(${htmlEscape(JSON.stringify(JSON.stringify(pinia.state.value)))});</script>`);
Object.assign(ctx, { $p: pinia.state.value });
await stream.write(`<script type="application/json" data-ssr="true" id="__APP_DATA__" nonce="${nonce}">${htmlEscape((JSON.stringify(ctx)))}</script>`);
await stream.write("</body></html>");
});
})

View File

@@ -24,6 +24,7 @@ export function createApp() {
preset: Aura,
options: {
darkModeSelector: '.my-app-dark',
cssLayer: false,
// cssLayer: {
// name: 'primevue',
// order: 'theme, base, primevue'
@@ -32,15 +33,18 @@ export function createApp() {
}
});
app.use(ToastService);
app.directive('no-hydrate', {
app.directive('nh', {
created(el) {
el.__v_skip = true;
}
});
app.directive("tooltip", Tooltip)
if (!import.meta.env.SSR) {
if ((window as any).__PINIA_STATE__ ) {
pinia.state.value = (window as any).__PINIA_STATE__;
Object.entries(JSON.parse(document.getElementById("__APP_DATA__")?.innerText || "{}")).forEach(([key, value]) => {
(window as any)[key] = value;
});
if ((window as any).$p ) {
pinia.state.value = (window as any).$p;
}
}
app.use(pinia);

View File

@@ -11,7 +11,10 @@
{{ content[route.name as keyof typeof content]?.subtitle || '' }}
</p>
<vue-head :input="{
title: content[route.name as keyof typeof content]?.headTitle || 'Authentication'
title: content[route.name as keyof typeof content]?.headTitle || 'Authentication',
meta: [
{ name: 'description', content: content[route.name as keyof typeof content]?.subtitle || '' }
]
}" />
</div>
<router-view />

View File

@@ -67,33 +67,57 @@ const routes: RouteData[] = [
path: "",
name: "overview",
component: () => import("./add/Add.vue"),
beforeEnter: (to, from, next) => {
const head = inject(headSymbol);
(head as any).push({
meta: {
head: {
title: 'Overview - Holistream',
});
next();
},
}
},
{
path: "upload",
name: "upload",
component: () => import("./add/Add.vue"),
meta: {
head: {
title: 'Upload - Holistream',
},
}
},
{
path: "video",
name: "video",
component: () => import("./add/Add.vue"),
meta: {
head: {
title: 'Videos - Holistream',
meta: [
{ name: 'description', content: 'Manage your video content.' },
],
},
}
},
{
path: "add",
name: "add",
path: "plans",
name: "plans",
component: () => import("./add/Add.vue"),
meta: {
head: {
title: 'Plans & Billing',
meta: [
{ name: 'description', content: 'Manage your plans and billing information.' },
],
},
}
},
{
path: "notification",
name: "notification",
component: () => import("./add/Add.vue"),
meta: {
head: {
title: 'Notification - Holistream',
},
}
},
],
},
@@ -115,6 +139,8 @@ const router = createRouter({
router.beforeEach((to, from, next) => {
const auth = useAuthStore();
const head = inject(headSymbol);
(head as any).push(to.meta.head || {});
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!auth.user) {
next({ name: "login" });

View File

@@ -55,47 +55,30 @@ export const useAuthStore = defineStore('auth', () => {
}).finally(() => {
loading.value = false;
});
// try {
// const response = await client.login(username, password);
// user.value = response.user;
// csrfToken.value = response.csrfToken;
// router.push('/');
// } catch (e: any) {
// // console.log(JSON.parse(e.message))
// // error.value = e.message || 'Login failed';
// error.value = 'Login failed';
// throw e;
// } finally {
// loading.value = false;
// }
}
async function register(username: string, email: string, password: string) {
loading.value = true;
error.value = null;
try {
const response = await client.register({ username, email, password });
return client.register({ username, email, password }).then((response) => {
user.value = response.user;
csrfToken.value = response.csrfToken;
router.push('/');
} catch (e: any) {
}).catch((e: any) => {
// error.value = e.message || 'Registration failed';
error.value = 'Registration failed';
throw e;
} finally {
}).finally(() => {
loading.value = false;
}
});
}
async function logout() {
try {
await client.logout();
} catch (e) {
// Ignore errors on logout
}
user.value = null;
csrfToken.value = null;
router.push('/');
return client.logout().then(() => {
user.value = null;
csrfToken.value = null;
router.push('/');
})
}
return { user, loading, error, csrfToken, initialized, init, login, register, logout, $reset: () => {

View File

@@ -93,7 +93,9 @@ export default defineConfig({
],
["animate-loadingBar", ["animation", "loadingBar 1.5s linear infinite"]],
],
transformers: [transformerVariantGroup(), transformerCompileClass()],
transformers: [transformerVariantGroup(), transformerCompileClass({
classPrefix: "_",
})],
preflights: [
{
getCSS: (context) => {