feat: use nuxt 4 structure

This commit is contained in:
Anthony Fu committed 2024-08-14 14:29:01 +02:00
1 parent 3f192323d8
commit fe3b8ce1c1
18 files changed
+7 -3

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { appName } from '~/constants'
useHead({
title: appName,
})
</script>
<template>
<VitePwaManifest />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<style>
html,
body,
#__nuxt {
height: 100vh;
margin: 0;
padding: 0;
}
html.dark {
background: #222;
color: white;
}
</style>
+17
View File
@@ -0,0 +1,17 @@
<script setup lang='ts'>
const { count, inc, dec } = useCount()
</script>
<template>
<div inline-flex m="y-3">
<button rounded-full p-2 btn @click="dec()">
<div i-carbon-subtract />
</button>
<div font="mono" w="15" m-auto inline-block>
{{ count }}
</div>
<button rounded-full p-2 btn @click="inc()">
<div i-carbon-add />
</button>
</div>
</template>
+21
View File
@@ -0,0 +1,21 @@
<script setup lang="ts">
const color = useColorMode()
useHead({
meta: [{
id: 'theme-color',
name: 'theme-color',
content: () => color.value === 'dark' ? '#222222' : '#ffffff',
}],
})
function toggleDark() {
color.preference = color.value === 'dark' ? 'light' : 'dark'
}
</script>
<template>
<button class="!outline-none" @click="toggleDark">
<div class="i-carbon-sun dark:i-carbon-moon" />
</button>
</template>
+7
View File
@@ -0,0 +1,7 @@
<template>
<div text="xl gray4" m-5 flex="~ gap3" justify-center>
<NuxtLink i-carbon-campsite to="/" />
<a i-carbon-logo-github href="https://github.com/antfu/vitesse-nuxt3" target="_blank" />
<DarkToggle />
</div>
</template>
+34
View File
@@ -0,0 +1,34 @@
<script setup lang="ts">
const name = ref('')
const router = useRouter()
function go() {
if (name.value)
router.push(`/hi/${encodeURIComponent(name.value)}`)
}
</script>
<template>
<div>
<input
id="input"
v-model="name"
placeholder="What's your name?"
type="text" autocomplete="off"
p="x-4 y-2" m="t-5" w="250px"
text="center" bg="transparent"
border="~ rounded gray-200 dark:gray-700"
outline="none active:none"
@keydown.enter="go"
>
<div>
<button
m-3 text-sm btn
:disabled="!name"
@click="go"
>
GO
</button>
</div>
</div>
</template>
+17
View File
@@ -0,0 +1,17 @@
<template>
<div inline-flex cursor-default text-2xl font-300>
<div flex flex-col children:mx-auto>
<img inline-block h-18 w-18 src="/nuxt.svg">
<span mt--2 text-green5>Nuxt 3</span>
</div>
<div
text="3xl gray4"
m="x-4 y-auto"
i-carbon-add transform transition-all-500 hover:rotate-135
/>
<div flex flex-col children:mx-auto>
<img inline-block h-18 w-18 src="/vite.png">
<span mt--2 text-purple5>Vitesse</span>
</div>
</div>
</template>
+13
View File
@@ -0,0 +1,13 @@
<script setup lang="ts">
const { data } = await useFetch('/api/pageview')
const time = useTimeAgo(() => data.value?.startAt || 0)
</script>
<template>
<div text-gray:80>
<span text-gray font-500>{{ data?.pageview }}</span>
page views since
<span text-gray>{{ time }}</span>
</div>
</template>
+16
View File
@@ -0,0 +1,16 @@
export function useCount() {
const count = useState('count', () => Math.round(Math.random() * 20))
function inc() {
count.value += 1
}
function dec() {
count.value -= 1
}
return {
count,
inc,
dec,
}
}
+34
View File
@@ -0,0 +1,34 @@
import { acceptHMRUpdate, defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
/**
* Current named of the user.
*/
const savedName = ref('')
const previousNames = ref(new Set<string>())
const usedNames = computed(() => Array.from(previousNames.value))
const otherNames = computed(() => usedNames.value.filter(name => name !== savedName.value))
/**
* Changes the current name of the user and saves the one that was used
* before.
*
* @param name - new name to set
*/
function setNewName(name: string) {
if (savedName.value)
previousNames.value.add(savedName.value)
savedName.value = name
}
return {
setNewName,
otherNames,
savedName,
}
})
if (import.meta.hot)
import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot))
+79
View File
@@ -0,0 +1,79 @@
import process from 'node:process'
import type { ModuleOptions } from '@vite-pwa/nuxt'
import { appDescription, appName } from '../constants/index'
const scope = '/'
export const pwa: ModuleOptions = {
registerType: 'autoUpdate',
scope,
base: scope,
manifest: {
id: scope,
scope,
name: appName,
short_name: appName,
description: appDescription,
theme_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: 'maskable-icon.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable',
},
],
},
workbox: {
globPatterns: ['**/*.{js,css,html,txt,png,ico,svg}'],
navigateFallbackDenylist: [/^\/api\//],
navigateFallback: '/',
cleanupOutdatedCaches: true,
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts.googleapis.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
{
urlPattern: /^https:\/\/fonts.gstatic.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'gstatic-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
},
registerWebManifestInRouteRules: true,
writePlugin: true,
devOptions: {
enabled: process.env.VITE_PLUGIN_PWA === 'true',
navigateFallback: scope,
},
}
+2
View File
@@ -0,0 +1,2 @@
export const appName = 'Vitesse for Nuxt 3'
export const appDescription = 'Vitesse for Nuxt 3'
+15
View File
@@ -0,0 +1,15 @@
## Layouts
Vue components in this dir are used as layouts.
By default, `default.vue` will be used unless an alternative is specified in the route meta.
```vue
<script setup lang="ts">
definePageMeta({
layout: 'home',
})
</script>
```
Learn more on https://nuxt.com/docs/guide/directory-structure/layouts
+9
View File
@@ -0,0 +1,9 @@
<template>
<main class="px-10 py-20 text-center">
<slot />
<Footer />
<div class="mx-auto mt-5 text-center text-sm opacity-25">
[Default Layout]
</div>
</main>
</template>
+9
View File
@@ -0,0 +1,9 @@
<template>
<main class="px-10 py-20 text-center">
<slot />
<Footer />
<div class="mx-auto mt-5 text-center text-sm opacity-25">
[Home Layout]
</div>
</main>
</template>
+17
View File
@@ -0,0 +1,17 @@
<script setup lang="ts">
const router = useRouter()
</script>
<template>
<main p="x4 y10" text="center teal-700 dark:gray-200">
<div text-4xl>
<div i-carbon-warning inline-block />
</div>
<div>Not found</div>
<div>
<button text-sm btn m="3 t8" @click="router.back()">
Back
</button>
</div>
</main>
</template>
+49
View File
@@ -0,0 +1,49 @@
<script setup lang="ts">
const route = useRoute<'hi-id'>()
const user = useUserStore()
const name = route.params.id
watchEffect(() => {
user.setNewName(route.params.id as string)
})
definePageMeta({
layout: 'home',
})
</script>
<template>
<div>
<div i-twemoji:waving-hand inline-block animate-shake-x animate-duration-5000 text-4xl />
<h3 text-2xl font-500>
Hi,
</h3>
<div text-xl>
{{ name }}!
</div>
<template v-if="user.otherNames.length">
<p my-4 text-sm>
<span op-50>Also as known as:</span>
<ul>
<li v-for="otherName in user.otherNames" :key="otherName">
<router-link :to="`/hi/${otherName}`" replace>
{{ otherName }}
</router-link>
</li>
</ul>
</p>
</template>
<Counter />
<div>
<NuxtLink
class="m-3 text-sm btn"
to="/"
>
Back
</NuxtLink>
</div>
</div>
</template>
+27
View File
@@ -0,0 +1,27 @@
<script setup lang="ts">
definePageMeta({
layout: 'home',
})
const online = useOnline()
</script>
<template>
<div>
<Logos mb-6 />
<Suspense>
<ClientOnly>
<PageView v-if="online" />
<div v-else text-gray:80>
You're offline
</div>
</ClientOnly>
<template #fallback>
<div italic op50>
<span animate-pulse>Loading...</span>
</div>
</template>
</Suspense>
<InputEntry />
</div>
</template>