change color

This commit is contained in:
2026-01-26 18:23:32 +07:00
parent fc86b3472e
commit 4cc2cc0691
11 changed files with 106 additions and 59 deletions

2
components.d.ts vendored
View File

@@ -14,6 +14,7 @@ declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
Add: typeof import('./src/components/icons/Add.vue')['default'] Add: typeof import('./src/components/icons/Add.vue')['default']
AlertTriangleIcon: typeof import('./src/components/icons/AlertTriangleIcon.vue')['default'] AlertTriangleIcon: typeof import('./src/components/icons/AlertTriangleIcon.vue')['default']
ArrowDownTray: typeof import('./src/components/icons/ArrowDownTray.vue')['default']
ArrowRightIcon: typeof import('./src/components/icons/ArrowRightIcon.vue')['default'] ArrowRightIcon: typeof import('./src/components/icons/ArrowRightIcon.vue')['default']
Bell: typeof import('./src/components/icons/Bell.vue')['default'] Bell: typeof import('./src/components/icons/Bell.vue')['default']
Button: typeof import('primevue/button')['default'] Button: typeof import('primevue/button')['default']
@@ -61,6 +62,7 @@ declare module 'vue' {
declare global { declare global {
const Add: typeof import('./src/components/icons/Add.vue')['default'] const Add: typeof import('./src/components/icons/Add.vue')['default']
const AlertTriangleIcon: typeof import('./src/components/icons/AlertTriangleIcon.vue')['default'] const AlertTriangleIcon: typeof import('./src/components/icons/AlertTriangleIcon.vue')['default']
const ArrowDownTray: typeof import('./src/components/icons/ArrowDownTray.vue')['default']
const ArrowRightIcon: typeof import('./src/components/icons/ArrowRightIcon.vue')['default'] const ArrowRightIcon: typeof import('./src/components/icons/ArrowRightIcon.vue')['default']
const Bell: typeof import('./src/components/icons/Bell.vue')['default'] const Bell: typeof import('./src/components/icons/Bell.vue')['default']
const Button: typeof import('primevue/button')['default'] const Button: typeof import('primevue/button')['default']

View File

@@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { VNode } from 'vue'; import { VNode } from 'vue';
import VueHead from '@/components/VueHead';
interface Breadcrumb { interface Breadcrumb {
label: string; label: string;
@@ -16,7 +15,7 @@ interface Action {
} }
interface Props { interface Props {
title: string; title: string | VNode;
description?: string; description?: string;
breadcrumbs?: Breadcrumb[]; breadcrumbs?: Breadcrumb[];
actions?: Action[]; actions?: Action[];
@@ -67,8 +66,8 @@ const getButtonClass = (variant?: string) => {
<!-- Title & Actions --> <!-- Title & Actions -->
<div class="flex items-start justify-between gap-4 flex-wrap"> <div class="flex items-start justify-between gap-4 flex-wrap">
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<h1 class="text-3xl font-bold text-gray-900 mb-1">{{ title }}</h1> <h1 v-if="typeof props.title == 'string'" class="text-3xl font-bold text-gray-900 mb-1">{{ title }}</h1>
<vue-head :input="{ title, meta: [{ name: 'description', content: description || '' }] }" /> <component v-else :is="title" />
<p v-if="description" class="text-gray-600">{{ description }}</p> <p v-if="description" class="text-gray-600">{{ description }}</p>
</div> </div>

View File

@@ -0,0 +1,17 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
v-if="!filled">
<path stroke-linecap="round" stroke-linejoin="round"
d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" v-else>
<path fill-rule="evenodd"
d="M12 2.25a.75.75 0 0 1 .75.75v11.69l3.22-3.22a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 1 1 1.06-1.06l3.22 3.22V3a.75.75 0 0 1 .75-.75Zm-9 13.5a.75.75 0 0 1 .75.75v2.25a1.5 1.5 0 0 0 1.5 1.5h13.5a1.5 1.5 0 0 0 1.5-1.5V16.5a.75.75 0 0 1 1.5 0v2.25a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V16.5a.75.75 0 0 1 .75-.75Z"
clip-rule="evenodd" />
</svg>
</template>
<script lang="ts" setup>
defineProps<{
filled?: boolean
}>()
</script>

View File

@@ -1,13 +1,12 @@
<script setup lang="ts"> <script setup lang="tsx">
import { client, type ModelVideo } from '@/api/client'; import { client, type ModelVideo } from '@/api/client';
import PageHeader from '@/components/dashboard/PageHeader.vue'; import PageHeader from '@/components/dashboard/PageHeader.vue';
import { useAuthStore } from '@/stores/auth';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import NameGradient from './components/NameGradient.vue';
import QuickActions from './components/QuickActions.vue'; import QuickActions from './components/QuickActions.vue';
import RecentVideos from './components/RecentVideos.vue'; import RecentVideos from './components/RecentVideos.vue';
import StatsOverview from './components/StatsOverview.vue'; import StatsOverview from './components/StatsOverview.vue';
const auth = useAuthStore()
const loading = ref(true); const loading = ref(true);
const recentVideos = ref<ModelVideo[]>([]); const recentVideos = ref<ModelVideo[]>([]);
@@ -53,12 +52,12 @@ const fetchDashboardData = async () => {
onMounted(() => { onMounted(() => {
fetchDashboardData(); fetchDashboardData();
}); });
</script> </script>
<template> <template>
<div class="dashboard-overview"> <div class="dashboard-overview">
<PageHeader :title="`Welcome back, ${auth.user?.username}! 👋`" description="Here's what's happening with your videos." <PageHeader :title="NameGradient" description="Welcome back, Here's what's happening with your videos." :breadcrumbs="[
:breadcrumbs="[
{ label: 'Dashboard' } { label: 'Dashboard' }
]" /> ]" />

View File

@@ -0,0 +1,10 @@
<template>
<div class="text-3xl font-bold text-gray-900 mb-1">
<span class=":uno: bg-[linear-gradient(130deg,#14a74b_0%,#22c55e_35%,#10b981_65%,#06b6d4_100%)] bg-clip-text text-transparent">Hello, {{ auth.user?.username }}</span>
</div>
</template>
<script setup lang="ts">
import { useAuthStore } from '@/stores/auth';
const auth = useAuthStore()
</script>

View File

@@ -29,19 +29,38 @@ const getStatusSeverity = (status: string) => {
return 'info'; return 'info';
} }
}; };
import { useToast } from 'primevue/usetoast';
import ArrowDownTray from '@/components/icons/ArrowDownTray.vue';
const toast = useToast();
const downloadInvoice = (item: PaymentHistoryItem) => {
toast.add({
severity: 'info',
summary: 'Downloading',
detail: `Downloading invoice #${item.invoiceId}...`,
life: 2000
});
// Simulate download delay
setTimeout(() => {
toast.add({
severity: 'success',
summary: 'Downloaded',
detail: `Invoice #${item.invoiceId} downloaded successfully`,
life: 3000
});
}, 1500);
};
</script> </script>
<template> <template>
<section> <section>
<h2 class="text-2xl font-bold mb-6 text-gray-900">Billing History</h2> <h2 class="text-2xl font-bold mb-6 text-gray-900">Billing History</h2>
<div class="bg-white border border-gray-200 rounded-xl overflow-hidden shadow-sm"> <div class="bg-white border border-gray-200 rounded-xl overflow-hidden">
<DataTable :value="history" tableStyle="min-width: 50rem" <DataTable :value="history" responsiveLayout="scroll" class="w-full">
:pt="{
thead: { class: 'bg-gray-50 border-b border-gray-200' },
headerRow: { class: 'text-gray-500 text-xs font-semibold uppercase tracking-wider' },
bodyRow: { class: 'text-gray-700 hover:bg-gray-50/50' }
}"
>
<template #empty> <template #empty>
<div class="text-center py-8 text-gray-500">No payment history found.</div> <div class="text-center py-8 text-gray-500">No payment history found.</div>
</template> </template>
@@ -54,19 +73,20 @@ const getStatusSeverity = (status: string) => {
<Column field="plan" header="Plan"></Column> <Column field="plan" header="Plan"></Column>
<Column field="status" header="Status"> <Column field="status" header="Status">
<template #body="slotProps"> <template #body="slotProps">
<Tag <Tag :value="slotProps.data.status" :severity="getStatusSeverity(slotProps.data.status)"
:value="slotProps.data.status" class="capitalize px-2 py-0.5 text-xs" :rounded="true" />
:severity="getStatusSeverity(slotProps.data.status)"
class="capitalize px-2 py-0.5 text-xs"
:rounded="true"
/>
</template> </template>
</Column> </Column>
<Column header="" style="width: 3rem"> <!-- <Column header="" style="width: 3rem">
<template #body> <template #body="slotProps">
<Button icon="i-heroicons-arrow-down-tray" text rounded severity="secondary" size="small" /> <Button text rounded severity="secondary" size="small" @click="downloadInvoice(slotProps.data)"
v-tooltip="'Download Invoice'">
<template #icon>
<ArrowDownTray class="w-5 h-5" />
</template> </template>
</Column> </Button>
</template>
</Column> -->
</DataTable> </DataTable>
</div> </div>
</section> </section>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { formatBytes } from '@/lib/utils';
import ProgressBar from 'primevue/progressbar'; import ProgressBar from 'primevue/progressbar';
import { computed } from 'vue'; import { computed } from 'vue';
import { formatBytes } from '@/lib/utils';
const props = defineProps<{ const props = defineProps<{
storageUsed: number; storageUsed: number;
@@ -15,7 +15,7 @@ const uploadsPercentage = computed(() => Math.min(Math.round((props.uploadsUsed
</script> </script>
<template> <template>
<div class="bg-white border border-gray-200 rounded-2xl p-8 shadow-sm flex flex-col justify-center"> <div class="bg-white border border-gray-200 rounded-2xl p-8 flex flex-col justify-center">
<h3 class="text-lg font-bold text-gray-900 mb-6">Usage Statistics</h3> <h3 class="text-lg font-bold text-gray-900 mb-6">Usage Statistics</h3>
<div class="mb-6"> <div class="mb-6">

View File

@@ -21,7 +21,7 @@ const formatBytes = (bytes: number) => {
</script> </script>
<template> <template>
<div class="bg-white border border-gray-200 rounded-2xl p-6 shadow-sm"> <div class="bg-white border border-gray-200 rounded-2xl p-6">
<h3 class="text-lg font-bold text-gray-900 mb-4">Account Status</h3> <h3 class="text-lg font-bold text-gray-900 mb-4">Account Status</h3>
<div class="space-y-4"> <div class="space-y-4">
<div> <div>

View File

@@ -3,7 +3,7 @@ import Tag from 'primevue/tag';
</script> </script>
<template> <template>
<div class="bg-white border border-gray-200 rounded-2xl p-6 shadow-sm"> <div class="bg-white border border-gray-200 rounded-2xl p-6">
<h3 class="text-lg font-bold text-gray-900 mb-4">Linked Accounts</h3> <h3 class="text-lg font-bold text-gray-900 mb-4">Linked Accounts</h3>
<div class="space-y-3"> <div class="space-y-3">
<div class="flex items-center justify-between p-3 rounded-lg border border-gray-100 hover:border-gray-200 transition-colors"> <div class="flex items-center justify-between p-3 rounded-lg border border-gray-100 hover:border-gray-200 transition-colors">

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ModelUser } from '@/api/client'; import type { ModelUser } from '@/api/client';
import InputText from 'primevue/inputtext';
import Button from 'primevue/button'; import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
defineProps<{ defineProps<{
user: ModelUser | null; user: ModelUser | null;
@@ -14,7 +14,7 @@ const emit = defineEmits<{
</script> </script>
<template> <template>
<div class="bg-white border border-gray-200 rounded-2xl p-8 shadow-sm"> <div class="bg-white border border-gray-200 rounded-2xl p-8">
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h3 class="text-xl font-bold text-gray-900">Personal Information</h3> <h3 class="text-xl font-bold text-gray-900">Personal Information</h3>
<div class="flex gap-2"> <div class="flex gap-2">

View File

@@ -45,18 +45,18 @@ export default defineConfig({
dark: "#14532d", dark: "#14532d",
}, },
accent: { accent: {
DEFAULT: "#6366f1", DEFAULT: "#14a74b",
50: "#eef2ff", 50: "#ecfdf3",
100: "#e0e7ff", 100: "#d1fae5",
200: "#c7d2fe", 200: "#a7f3d0",
300: "#a5b4fc", 300: "#6ee7b7",
400: "#818cf8", 400: "#34d399",
500: "#6366f1", 500: "#14a74b",
600: "#4f46e5", 600: "#0f8a3d",
700: "#4338ca", 700: "#0c6f33",
800: "#3730a3", 800: "#095a2a",
900: "#312e81", 900: "#064622",
950: "#1e1b4b", 950: "#032814",
}, },
success: { success: {
DEFAULT: "#22c55e", DEFAULT: "#22c55e",