Skip to content

Commit d9cef53

Browse files
committed
feat: dashboard
1 parent d3a51ba commit d9cef53

File tree

14 files changed

+845
-11
lines changed

14 files changed

+845
-11
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
},
1212
"dependencies": {
1313
"@inertiajs/vue3": "^2.0.17",
14-
"@nuxt/ui-pro": "^3.3.0"
14+
"@nuxt/ui-pro": "^3.3.0",
15+
"@vueuse/core": "^13.6.0"
1516
},
1617
"devDependencies": {
1718
"@antfu/eslint-config": "^5.2.1",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/components/AppHeader.vue

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ import { login, register } from '@/routes'
33
44
const items = computed(() => [{
55
label: 'Docs',
6-
to: '/docs',
76
}, {
87
label: 'Pricing',
9-
to: '/pricing',
108
}, {
119
label: 'Blog',
1210
to: '/blog',
1311
}, {
1412
label: 'Changelog',
15-
to: '/changelog',
1613
badge: {
1714
label: 'New',
1815
color: 'primary' as const,
@@ -42,15 +39,15 @@ const items = computed(() => [{
4239
icon="i-lucide-log-in"
4340
color="neutral"
4441
variant="ghost"
45-
to="/login"
42+
:to="login().url"
4643
class="lg:hidden"
4744
/>
4845

4946
<UButton
5047
label="Sign in"
5148
color="neutral"
5249
variant="outline"
53-
to="/login"
50+
:to="login().url"
5451
class="hidden lg:inline-flex"
5552
/>
5653

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<UPageCard
3+
variant="subtle"
4+
>
5+
<div class="relative overflow-hidden rounded-sm border border-dashed border-accented opacity-75 px-4 flex items-center justify-center aspect-video">
6+
<svg
7+
class="absolute inset-0 h-full w-full stroke-inverted/10"
8+
fill="none"
9+
>
10+
<defs>
11+
<pattern
12+
id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"
13+
x="0"
14+
y="0"
15+
width="10"
16+
height="10"
17+
patternUnits="userSpaceOnUse"
18+
>
19+
<path d="M-3 13 15-5M-5 5l18-18M-1 21 17 3" />
20+
</pattern>
21+
</defs>
22+
<rect
23+
stroke="none"
24+
fill="url(#pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e)"
25+
width="100%"
26+
height="100%"
27+
/>
28+
</svg>
29+
30+
<slot />
31+
</div>
32+
</UPageCard>
33+
</template>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<template>
2+
<div class="relative">
3+
<UPageCard
4+
variant="subtle"
5+
class="rounded-2xl"
6+
>
7+
<video
8+
class="rounded-xl"
9+
data-v-baf90ddd=""
10+
preload="none"
11+
poster="https://res.cloudinary.com/nuxt/video/upload/so_3.3/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.jpg"
12+
:controls="true"
13+
><source
14+
data-v-baf90ddd=""
15+
src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.webm"
16+
type="video/webm"
17+
><source
18+
data-v-baf90ddd=""
19+
src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.mp4"
20+
type="video/mp4"
21+
><source
22+
data-v-baf90ddd=""
23+
src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.ogg"
24+
type="video/ogg"
25+
>
26+
</video>
27+
</UPageCard>
28+
</div>
29+
</template>
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<script setup lang="ts">
2+
interface Star {
3+
x: number
4+
y: number
5+
size: number
6+
}
7+
8+
const props = withDefaults(defineProps<{
9+
starCount?: number
10+
color?: string
11+
speed?: 'slow' | 'normal' | 'fast'
12+
size?: { min: number, max: number }
13+
}>(), {
14+
starCount: 300,
15+
color: 'var(--ui-primary)',
16+
speed: 'normal',
17+
size: () => ({
18+
min: 1,
19+
max: 2,
20+
}),
21+
})
22+
23+
// Generate random star positions and sizes
24+
function generateStars(count: number): Star[] {
25+
return Array.from({ length: count }, () => ({
26+
x: Math.floor(Math.random() * 2000),
27+
y: Math.floor(Math.random() * 2000),
28+
size: typeof props.size === 'number'
29+
? props.size
30+
: Math.random() * (props.size.max - props.size.min) + props.size.min,
31+
}))
32+
}
33+
34+
// Define speed configurations once
35+
const speedMap = {
36+
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
37+
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
38+
fast: { duration: 100, opacity: 1, ratio: 0.4 },
39+
}
40+
41+
// Use a more efficient approach to generate and store stars
42+
const stars = ref<{ slow: Star[], normal: Star[], fast: Star[] }>({
43+
slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
44+
normal: generateStars(Math.floor(props.starCount * speedMap.normal.ratio)),
45+
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio)),
46+
})
47+
48+
// Compute star layers with different speeds and opacities
49+
const starLayers = computed(() => [
50+
{ stars: stars.value.fast, ...speedMap.fast },
51+
{ stars: stars.value.normal, ...speedMap.normal },
52+
{ stars: stars.value.slow, ...speedMap.slow },
53+
])
54+
</script>
55+
56+
<template>
57+
<div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden">
58+
<div class="stars size-full absolute inset-x-0 top-0">
59+
<div
60+
v-for="(layer, index) in starLayers"
61+
:key="index"
62+
class="star-layer"
63+
:style="{
64+
'--star-duration': `${layer.duration}s`,
65+
'--star-opacity': layer.opacity,
66+
'--star-color': color,
67+
}"
68+
>
69+
<div
70+
v-for="(star, starIndex) in layer.stars"
71+
:key="starIndex"
72+
class="star absolute rounded-full"
73+
:style="{
74+
left: `${star.x}px`,
75+
top: `${star.y}px`,
76+
width: `${star.size}px`,
77+
height: `${star.size}px`,
78+
backgroundColor: 'var(--star-color)',
79+
opacity: 'var(--star-opacity)',
80+
}"
81+
/>
82+
</div>
83+
</div>
84+
</div>
85+
</template>
86+
87+
<style scoped>
88+
.stars {
89+
left: 50%;
90+
transform: translate(-50%);
91+
-webkit-mask-image: linear-gradient(180deg,
92+
rgba(217, 217, 217, 0) 0%,
93+
rgba(217, 217, 217, 0.8) 25%,
94+
#d9d9d9 50%,
95+
rgba(217, 217, 217, 0.8) 75%,
96+
rgba(217, 217, 217, 0) 100%);
97+
mask-image: linear-gradient(180deg,
98+
rgba(217, 217, 217, 0) 0%,
99+
rgba(217, 217, 217, 0.8) 25%,
100+
#d9d9d9 50%,
101+
rgba(217, 217, 217, 0.8) 75%,
102+
rgba(217, 217, 217, 0) 100%);
103+
-webkit-mask-size: cover;
104+
mask-size: cover;
105+
}
106+
107+
.star-layer {
108+
animation: risingStarsAnimation linear infinite;
109+
animation-duration: var(--star-duration);
110+
will-change: transform;
111+
}
112+
113+
@keyframes risingStarsAnimation {
114+
0% {
115+
transform: translateY(0);
116+
}
117+
118+
100% {
119+
transform: translateY(-2000px);
120+
}
121+
}
122+
</style>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<template>
2+
<UDropdownMenu
3+
v-slot="{ open }"
4+
:modal="false"
5+
:items="[{
6+
label: 'Starter',
7+
to: 'https://starter-template.nuxt.dev/',
8+
}, {
9+
label: 'Landing',
10+
to: 'https://landing-template.nuxt.dev/',
11+
}, {
12+
label: 'Docs',
13+
to: 'https://docs-template.nuxt.dev/',
14+
}, {
15+
label: 'SaaS',
16+
to: 'https://saas-template.nuxt.dev/',
17+
color: 'primary',
18+
checked: true,
19+
type: 'checkbox',
20+
}, {
21+
label: 'Dashboard',
22+
to: 'https://dashboard-template.nuxt.dev/',
23+
}, {
24+
label: 'Chat',
25+
to: 'https://chat-template.nuxt.dev/',
26+
}]"
27+
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-0' }"
28+
size="xs"
29+
>
30+
<UButton
31+
label="SaaS"
32+
variant="subtle"
33+
trailing-icon="i-lucide-chevron-down"
34+
size="xs"
35+
class="-mb-[6px] font-semibold rounded-full truncate"
36+
:class="[open && 'bg-primary/15']"
37+
:ui="{
38+
trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' '),
39+
}"
40+
/>
41+
</UDropdownMenu>
42+
</template>

0 commit comments

Comments
 (0)