Change linter config to antfu config and lint code

This commit is contained in:
2024-07-24 02:01:30 +02:00
parent 45293e4982
commit 2331b01a8d
53 changed files with 1999 additions and 1556 deletions

View File

@@ -3,10 +3,10 @@ export default defineAppConfig({
gray: 'neutral', gray: 'neutral',
primary: 'gray', primary: 'gray',
container: { container: {
constrained: 'max-w-3xl' constrained: 'max-w-3xl',
}, },
icons: { icons: {
dynamic: true dynamic: true,
} },
} },
}) })

View File

@@ -1,3 +1,15 @@
<script lang="ts" setup>
useHead({
link: [{ rel: 'icon', type: 'image/png', href: '/favicon.png' }],
})
const head = useLocaleHead({
addDirAttribute: true,
identifierAttribute: 'id',
addSeoAttributes: true,
})
</script>
<template> <template>
<Html <Html
:dir="head.htmlAttrs.dir" :dir="head.htmlAttrs.dir"
@@ -40,18 +52,6 @@
</Html> </Html>
</template> </template>
<script lang="ts" setup>
useHead({
link: [{ rel: 'icon', type: 'image/png', href: '/favicon.png' }]
})
const head = useLocaleHead({
addDirAttribute: true,
identifierAttribute: 'id',
addSeoAttributes: true
})
</script>
<style> <style>
body { body {
font-family: 'DM Sans', sans-serif; font-family: 'DM Sans', sans-serif;

View File

@@ -3,26 +3,27 @@ const socials = [
{ {
icon: 'i-ph-x-logo-duotone', icon: 'i-ph-x-logo-duotone',
label: 'Twitter', label: 'Twitter',
link: 'https://twitter.com/ArthurDanj' link: 'https://twitter.com/ArthurDanj',
}, },
{ {
icon: 'i-ph-github-logo-duotone', icon: 'i-ph-github-logo-duotone',
label: 'GitHub', label: 'GitHub',
link: 'https://github.com/ArthurDanjou' link: 'https://github.com/ArthurDanjou',
}, },
{ {
icon: 'i-ph-linkedin-logo-duotone', icon: 'i-ph-linkedin-logo-duotone',
label: 'LinkedIn', label: 'LinkedIn',
link: 'https://www.linkedin.com/in/arthurdanjou/' link: 'https://www.linkedin.com/in/arthurdanjou/',
}, { },
{
icon: 'i-ph-discord-logo-duotone', icon: 'i-ph-discord-logo-duotone',
label: 'Discord', label: 'Discord',
link: 'https://discordapp.com/users/179635349100691456' link: 'https://discordapp.com/users/179635349100691456',
} },
] ]
const { t } = useI18n({ const { t } = useI18n({
useScope: 'local' useScope: 'local',
}) })
</script> </script>
@@ -63,7 +64,7 @@ const { t } = useI18n({
<div class="mt-8 w-full flex justify-center text-xs"> <div class="mt-8 w-full flex justify-center text-xs">
{{ {{
t('copyright', { t('copyright', {
date: new Date().getFullYear() date: new Date().getFullYear(),
}) })
}} }}
</div> </div>

View File

@@ -10,52 +10,52 @@ const navs = [
{ {
label: { label: {
en: 'home', en: 'home',
fr: 'accueil' fr: 'accueil',
}, },
to: '/', to: '/',
icon: 'i-ph-house-line-duotone', icon: 'i-ph-house-line-duotone',
shortcut: { shortcut: {
en: 'h', en: 'h',
fr: 'a' fr: 'a',
} },
}, },
{ {
label: { label: {
en: 'uses', en: 'uses',
fr: 'usages' fr: 'usages',
}, },
to: '/uses', to: '/uses',
icon: 'i-ph-backpack-duotone', icon: 'i-ph-backpack-duotone',
shortcut: { shortcut: {
en: 'u', en: 'u',
fr: 'u' fr: 'u',
} },
}, },
{ {
label: { label: {
en: 'writings', en: 'writings',
fr: 'écrits' fr: 'écrits',
}, },
to: '/writings', to: '/writings',
icon: 'i-ph-books-duotone', icon: 'i-ph-books-duotone',
shortcut: { shortcut: {
en: 'w', en: 'w',
fr: 'e' fr: 'e',
} },
}, },
{ {
label: { label: {
en: 'resume', en: 'resume',
fr: 'cv' fr: 'cv',
}, },
to: config.public.cloud.resume, to: config.public.cloud.resume,
target: '_blank', target: '_blank',
icon: 'i-ph-address-book-duotone', icon: 'i-ph-address-book-duotone',
shortcut: { shortcut: {
en: 'r', en: 'r',
fr: 'c' fr: 'c',
} },
} },
] ]
async function toggleTheme() { async function toggleTheme() {
@@ -69,6 +69,9 @@ async function toggleTheme() {
document.body.style.animation = '' document.body.style.animation = ''
} }
const { locale, setLocale, locales, t } = useI18n()
const currentLocale = computed(() => locales.value.filter(l => l.code === locale.value)[0])
async function changeLocale() { async function changeLocale() {
document.body.style.animation = 'switch-on .2s' document.body.style.animation = 'switch-on .2s'
await new Promise(resolve => setTimeout(resolve, 200)) await new Promise(resolve => setTimeout(resolve, 200))
@@ -81,8 +84,6 @@ async function changeLocale() {
} }
const router = useRouter() const router = useRouter()
const { locale, setLocale, locales, t } = useI18n()
const currentLocale = computed(() => locales.value.filter(l => l.code === locale.value)[0])
defineShortcuts({ defineShortcuts({
h: () => router.push('/'), h: () => router.push('/'),
a: () => router.push('/'), a: () => router.push('/'),
@@ -93,7 +94,7 @@ defineShortcuts({
c: () => window.open(config.public.cloud.resume, '_blank'), c: () => window.open(config.public.cloud.resume, '_blank'),
t: () => toggleTheme(), t: () => toggleTheme(),
l: () => changeLocale(), l: () => changeLocale(),
backspace: () => router.back() backspace: () => router.back(),
}) })
</script> </script>

View File

@@ -2,12 +2,12 @@
defineProps({ defineProps({
title: { title: {
type: String, type: String,
required: true required: true,
}, },
description: { description: {
type: String, type: String,
required: true required: true,
} },
}) })
</script> </script>

View File

@@ -9,7 +9,8 @@ const { locale, locales } = useI18n()
const currentLocale = computed(() => locales.value.find(l => l.code === locale.value)) const currentLocale = computed(() => locales.value.find(l => l.code === locale.value))
const getActivity = computed(() => { const getActivity = computed(() => {
if (!codingActivity.value) return if (!codingActivity.value)
return
const { name, details, state, timestamps } = codingActivity.value const { name, details, state, timestamps } = codingActivity.value
const isActive = name === 'Visual Studio Code' const isActive = name === 'Visual Studio Code'
@@ -44,14 +45,14 @@ const getActivity = computed(() => {
.trim(), .trim(),
formated: { formated: {
date: formatDate(timestamps.start, 'DD MMM YYYY'), date: formatDate(timestamps.start, 'DD MMM YYYY'),
time: formatDate(timestamps.start, 'HH:mm:ss') time: formatDate(timestamps.start, 'HH:mm:ss'),
} },
} },
} }
}) })
const { t } = useI18n({ const { t } = useI18n({
useScope: 'local' useScope: 'local',
}) })
</script> </script>

View File

@@ -1,3 +1,10 @@
<script lang="ts" setup>
const { width } = useWindowSize()
const { t } = useI18n({
useScope: 'local',
})
</script>
<template> <template>
<ClientOnly> <ClientOnly>
<div <div
@@ -13,13 +20,6 @@
</ClientOnly> </ClientOnly>
</template> </template>
<script lang="ts" setup>
const { width } = useWindowSize()
const { t } = useI18n({
useScope: 'local'
})
</script>
<i18n lang="json"> <i18n lang="json">
{ {
"en": { "en": {

View File

@@ -4,15 +4,15 @@ import type { PropType } from 'vue'
defineProps({ defineProps({
text: { text: {
type: [String, Number], type: [String, Number],
required: true required: true,
}, },
hover: { hover: {
type: String, type: String,
required: true required: true,
}, },
position: { position: {
type: String as PropType<'top' | 'right' | 'bottom' | 'left'> type: String as PropType<'top' | 'right' | 'bottom' | 'left'>,
} },
}) })
</script> </script>

View File

@@ -4,13 +4,13 @@ import type { PropType } from 'vue'
defineProps({ defineProps({
href: { href: {
type: String, type: String,
default: '' default: '',
}, },
target: { target: {
type: String as PropType<'_blank' | '_parent' | '_self' | '_top' | (string & object) | null | undefined>, type: String as PropType<'_blank' | '_parent' | '_self' | '_top' | (string & object) | null | undefined>,
default: undefined, default: undefined,
required: false required: false,
} },
}) })
</script> </script>

View File

@@ -1,3 +1,12 @@
<script lang="ts" setup>
import { computed, useRuntimeConfig } from '#imports'
const props = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)))
</script>
<template> <template>
<h2 <h2
:id="id" :id="id"
@@ -12,12 +21,3 @@
<slot v-else /> <slot v-else />
</h2> </h2>
</template> </template>
<script lang="ts" setup>
import { computed, useRuntimeConfig } from '#imports'
const props = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)))
</script>

View File

@@ -1,3 +1,12 @@
<script lang="ts" setup>
import { computed, useRuntimeConfig } from '#imports'
const props = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)))
</script>
<template> <template>
<h2 <h2
:id="id" :id="id"
@@ -12,12 +21,3 @@
<slot v-else /> <slot v-else />
</h2> </h2>
</template> </template>
<script lang="ts" setup>
import { computed, useRuntimeConfig } from '#imports'
const props = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)))
</script>

View File

@@ -2,8 +2,8 @@
defineProps({ defineProps({
icon: { icon: {
type: String, type: String,
required: true required: true,
} },
}) })
</script> </script>

View File

@@ -1,3 +1,9 @@
<script lang="ts" setup>
const { t } = useI18n({
useScope: 'local',
})
</script>
<template> <template>
<div class="flex items-center gap-2 mt-4"> <div class="flex items-center gap-2 mt-4">
<div class="flex items-center"> <div class="flex items-center">
@@ -17,12 +23,6 @@
</div> </div>
</template> </template>
<script lang="ts" setup>
const { t } = useI18n({
useScope: 'local'
})
</script>
<i18n lang="json"> <i18n lang="json">
{ {
"en": { "en": {

View File

@@ -3,7 +3,7 @@ import type { Stats } from '~~/types'
const { data: stats } = await useFetch<Stats>('/api/stats') const { data: stats } = await useFetch<Stats>('/api/stats')
const { t } = useI18n({ const { t } = useI18n({
useScope: 'local' useScope: 'local',
}) })
</script> </script>

View File

@@ -2,19 +2,19 @@
defineProps({ defineProps({
label: { label: {
type: String, type: String,
required: true required: true,
}, },
href: { href: {
type: String, type: String,
required: true required: true,
}, },
icon: { icon: {
type: String type: String,
}, },
blanked: { blanked: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}) })
</script> </script>

View File

@@ -5,8 +5,8 @@ import type { UsesItem } from '#components'
defineProps({ defineProps({
item: { item: {
type: Object as PropType<typeof UsesItem>, type: Object as PropType<typeof UsesItem>,
required: true required: true,
} },
}) })
const { locale } = useI18n() const { locale } = useI18n()

View File

@@ -1,3 +1,12 @@
<script lang="ts" setup>
defineProps({
title: {
type: String,
required: true,
},
})
</script>
<template> <template>
<div class="space-y-8"> <div class="space-y-8">
<UDivider <UDivider
@@ -9,12 +18,3 @@
</ul> </ul>
</div> </div>
</template> </template>
<script lang="ts" setup>
defineProps({
title: {
type: String,
required: true
}
})
</script>

View File

@@ -1,9 +1,9 @@
<script lang="ts" setup>
const { locale } = useI18n()
</script>
<template> <template>
<main class="!max-w-none prose dark:prose-invert"> <main class="!max-w-none prose dark:prose-invert">
<ContentDoc :path="`/home/${locale}`" /> <ContentDoc :path="`/home/${locale}`" />
</main> </main>
</template> </template>
<script lang="ts" setup>
const { locale } = useI18n()
</script>

View File

@@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
const { t } = useI18n({ const { t } = useI18n({
useScope: 'local' useScope: 'local',
}) })
useSeoMeta({ useSeoMeta({
title: 'Things I use', title: 'Things I use',
description: t('description') description: t('description'),
}) })
const { data: items } = await useAsyncData('uses', () => queryContent('/uses').find() const { data: items } = await useAsyncData('uses', () => queryContent('/uses').find(),
) )
const hardware = items.value!.filter(item => item.category === 'hardware') const hardware = items.value!.filter(item => item.category === 'hardware')

View File

@@ -3,33 +3,33 @@ const route = useRoute()
const { data: post } = await useAsyncData(`writing:${route.params.slug}`, () => queryContent(`/writings/${route.params.slug}`).findOne()) const { data: post } = await useAsyncData(`writing:${route.params.slug}`, () => queryContent(`/writings/${route.params.slug}`).findOne())
const { const {
data: postDB, data: postDB,
refresh refresh,
} = await useAsyncData(`writing:${route.params.slug}:db`, () => $fetch(`/api/posts/${route.params.slug}`, { method: 'POST' })) } = await useAsyncData(`writing:${route.params.slug}:db`, () => $fetch(`/api/posts/${route.params.slug}`, { method: 'POST' }))
const { locale, locales } = useI18n() const { locale, locales } = useI18n()
const currentLocale = computed(() => locales.value.filter(l => l.code === locale.value)[0]) const currentLocale = computed(() => locales.value.filter(l => l.code === locale.value)[0])
const { t } = useI18n({ const { t } = useI18n({
useScope: 'local' useScope: 'local',
}) })
function top() { function top() {
window.scrollTo({ window.scrollTo({
top: 0, top: 0,
left: 0, left: 0,
behavior: 'smooth' behavior: 'smooth',
}) })
} }
const { copy, copied } = useClipboard({ const { copy, copied } = useClipboard({
source: `https://arthurdanjou.fr/writings/${route.params.slug}`, source: `https://arthurdanjou.fr/writings/${route.params.slug}`,
copiedDuring: 4000 copiedDuring: 4000,
}) })
useSeoMeta({ useSeoMeta({
title: post.value?.title, title: post.value?.title,
description: post.value?.description, description: post.value?.description,
author: 'Arthur Danjou' author: 'Arthur Danjou',
}) })
function getDetails() { function getDetails() {
@@ -43,11 +43,12 @@ function getDetails() {
} }
const likeCookie = useCookie<boolean>(`post:like:${route.params.slug}`, { const likeCookie = useCookie<boolean>(`post:like:${route.params.slug}`, {
maxAge: 7200 maxAge: 7200,
}) })
async function handleLike() { async function handleLike() {
if (likeCookie.value) return if (likeCookie.value)
return
await $fetch(`/api/posts/like/${route.params.slug}`, { method: 'PUT' }) await $fetch(`/api/posts/like/${route.params.slug}`, { method: 'PUT' })
await refresh() await refresh()
likeCookie.value = true likeCookie.value = true
@@ -133,7 +134,7 @@ async function handleLike() {
<div class="flex gap-4 items-center flex-wrap"> <div class="flex gap-4 items-center flex-wrap">
<UButton <UButton
:label="postDB?.likes > 1 ? `${postDB?.likes} likes` : `${postDB?.likes} like`" :label="postDB?.likes > 1 ? `${postDB?.likes} likes` : `${postDB?.likes} like`"
:color="likeCookie ? 'red': 'white'" :color="likeCookie ? 'red' : 'white'"
icon="i-ph-heart-duotone" icon="i-ph-heart-duotone"
size="lg" size="lg"
variant="solid" variant="solid"

View File

@@ -1,23 +1,22 @@
<script setup lang="ts"> <script setup lang="ts">
const { t, locale } = useI18n({ const { t, locale } = useI18n({
useScope: 'local' useScope: 'local',
}) })
useSeoMeta({ useSeoMeta({
title: 'My Shelf', title: 'My Shelf',
description: t('description') description: t('description'),
}) })
const { data: writings } = await useAsyncData('all-writings', () => const { data: writings } = await useAsyncData('all-writings', () =>
queryContent('/writings').sort({ published: -1 }).without('body').find() queryContent('/writings').sort({ published: -1 }).without('body').find())
)
const { data: writingsDB } = await useAsyncData('all-writings-db', () => const { data: writingsDB } = await useAsyncData('all-writings-db', () =>
$fetch(`/api/posts`) $fetch(`/api/posts`))
)
function getDetails(slug: string) { function getDetails(slug: string) {
const writing = writingsDB.value!.find(writing => writing.slug === slug) const writing = writingsDB.value!.find(writing => writing.slug === slug)
if (!writing) return '' if (!writing)
return ''
const like = writing.likes! > 1 ? t('likes.many') : t('likes.one') const like = writing.likes! > 1 ? t('likes.many') : t('likes.one')
const view = writing.views! > 1 ? t('views.many') : t('views.one') const view = writing.views! > 1 ? t('views.many') : t('views.one')

View File

@@ -3,5 +3,5 @@ import type { Config } from 'drizzle-kit'
export default { export default {
dialect: 'sqlite', dialect: 'sqlite',
schema: './server/database/schema.ts', schema: './server/database/schema.ts',
out: './server/database/migrations' out: './server/database/migrations',
} satisfies Config } satisfies Config

View File

@@ -1,6 +1,5 @@
// @ts-check import antfu from '@antfu/eslint-config'
import withNuxt from './.nuxt/eslint.config.mjs'
export default withNuxt( export default antfu(
// Your custom configs here // Your custom configs here
) )

View File

@@ -6,22 +6,21 @@ export default defineNuxtConfig({
pageTransition: { name: 'page', mode: 'out-in' }, pageTransition: { name: 'page', mode: 'out-in' },
head: { head: {
templateParams: { templateParams: {
separator: '•' separator: '•',
} },
} },
}, },
// Nuxt Modules // Nuxt Modules
modules: [ modules: [
'@nuxthub/core', '@nuxthub/core',
'@nuxt/eslint',
'@nuxt/ui', '@nuxt/ui',
'@nuxt/content', '@nuxt/content',
'@vueuse/nuxt', '@vueuse/nuxt',
'@nuxtjs/google-fonts', '@nuxtjs/google-fonts',
'@nuxthq/studio', '@nuxthq/studio',
'@nuxt/image', '@nuxt/image',
'@nuxtjs/i18n' '@nuxtjs/i18n',
], ],
// Nuxt Hub // Nuxt Hub
@@ -29,26 +28,27 @@ export default defineNuxtConfig({
cache: true, cache: true,
kv: true, kv: true,
database: true, database: true,
analytics: true analytics: true,
}, },
// Nuxt Content // Nuxt Content
content: { content: {
highlight: { highlight: {
theme: 'github-dark' theme: 'github-dark',
} },
locales: ['en', 'fr'],
}, },
// Nuxt Color Mode // Nuxt Color Mode
colorMode: { colorMode: {
preference: 'system', preference: 'system',
fallback: 'light' fallback: 'light',
}, },
// Nuxt Devtools // Nuxt Devtools
devtools: { devtools: {
enabled: true, enabled: true,
timeline: { enabled: true } timeline: { enabled: true },
}, },
// Nuxt I18N // Nuxt I18N
@@ -58,24 +58,15 @@ export default defineNuxtConfig({
{ {
code: 'en', code: 'en',
iso: 'en-EN', iso: 'en-EN',
icon: 'i-twemoji-flag-united-kingdom' icon: 'i-twemoji-flag-united-kingdom',
}, { },
{
code: 'fr', code: 'fr',
iso: 'fr-FR', iso: 'fr-FR',
icon: 'i-twemoji-flag-france' icon: 'i-twemoji-flag-france',
} },
], ],
defaultLocale: 'en' defaultLocale: 'en',
},
// Nuxt Eslint
eslint: {
config: {
stylistic: {
quotes: 'single',
commaDangle: 'never'
}
}
}, },
// Nuxt Google Fonts // Nuxt Google Fonts
@@ -85,15 +76,15 @@ export default defineNuxtConfig({
'Inter': [400, 500, 600, 700, 800, 900], 'Inter': [400, 500, 600, 700, 800, 900],
'Sofia Sans': [400], 'Sofia Sans': [400],
'DM Sans': [400, 500, 600, 700, 800, 900], 'DM Sans': [400, 500, 600, 700, 800, 900],
'Dancing Script': [400, 700] 'Dancing Script': [400, 700],
} },
}, },
// Nitro // Nitro
nitro: { nitro: {
experimental: { experimental: {
openAPI: true openAPI: true,
} },
}, },
// Nuxt Env // Nuxt Env
@@ -101,21 +92,21 @@ export default defineNuxtConfig({
discord: { discord: {
userId: '', userId: '',
id: '', id: '',
token: '' token: '',
}, },
wakatime: { wakatime: {
userId: '', userId: '',
coding: '', coding: '',
editors: '', editors: '',
languages: '', languages: '',
os: '' os: '',
}, },
public: { public: {
cloud: { cloud: {
resume: '' resume: '',
} },
} },
}, },
compatibilityDate: '2024-07-08' compatibilityDate: '2024-07-08',
}) })

View File

@@ -1,7 +1,7 @@
{ {
"name": "artsite", "name": "artsite",
"private": true, "private": true,
"packageManager": "pnpm@9.4.0", "packageManager": "pnpm@9.5.0",
"scripts": { "scripts": {
"build": "nuxt build", "build": "nuxt build",
"dev": "nuxt dev --host", "dev": "nuxt dev --host",
@@ -9,34 +9,34 @@
"preview": "nuxt preview", "preview": "nuxt preview",
"postinstall": "nuxt prepare", "postinstall": "nuxt prepare",
"lint": "eslint .", "lint": "eslint .",
"lint:fix": "eslint --fix .",
"db:generate": "drizzle-kit generate" "db:generate": "drizzle-kit generate"
}, },
"dependencies": { "dependencies": {
"@iconify/json": "^2.2.225", "@iconify/json": "^2.2.230",
"@nuxt/content": "^2.13.1", "@nuxt/content": "^2.13.2",
"@nuxt/eslint": "^0.3.13",
"@nuxt/image": "^1.7.0", "@nuxt/image": "^1.7.0",
"@nuxt/ui": "^2.17.0", "@nuxt/ui": "^2.17.0",
"@nuxthq/studio": "^2.0.3", "@nuxthq/studio": "^2.0.3",
"@nuxthub/core": "^0.7.0", "@nuxthub/core": "^0.7.1",
"@nuxtjs/google-fonts": "^3.2.0", "@nuxtjs/google-fonts": "^3.2.0",
"@nuxtjs/i18n": "^8.3.1", "@nuxtjs/i18n": "^8.3.1",
"drizzle-orm": "^0.31.2", "drizzle-orm": "^0.31.4",
"h3-zod": "^0.5.3", "h3-zod": "^0.5.3",
"nuxt": "^3.12.3", "nuxt": "^3.12.4",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^2.23.2",
"@nuxt/devtools": "^1.3.9", "@nuxt/devtools": "^1.3.9",
"@nuxt/eslint-config": "^0.3.13",
"@nuxt/ui": "^2.17.0", "@nuxt/ui": "^2.17.0",
"@types/node": "^20.14.10", "@types/node": "^20.14.12",
"@vueuse/core": "^10.11.0", "@vueuse/core": "^10.11.0",
"@vueuse/nuxt": "^10.11.0", "@vueuse/nuxt": "^10.11.0",
"drizzle-kit": "^0.22.8", "drizzle-kit": "^0.22.8",
"eslint": "^9.6.0", "eslint": "^9.7.0",
"typescript": "^5.5.3", "typescript": "^5.5.4",
"vue-tsc": "^2.0.26", "vue-tsc": "^2.0.28",
"wrangler": "^3.63.1" "wrangler": "^3.66.0"
} }
} }

3123
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,16 +2,16 @@ import { useValidatedParams, z } from 'h3-zod'
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
const { slug } = await useValidatedParams(event, { const { slug } = await useValidatedParams(event, {
slug: z.string() slug: z.string(),
}) })
return useDB().insert(tables.posts).values({ return useDB().insert(tables.posts).values({
slug slug,
}).onConflictDoUpdate({ }).onConflictDoUpdate({
target: tables.posts.slug, target: tables.posts.slug,
set: { set: {
slug, slug,
views: sql`${tables.posts.views} views: sql`${tables.posts.views}
+ 1` + 1`,
} },
}).returning().get() }).returning().get()
}) })

View File

@@ -2,12 +2,12 @@ import { useValidatedParams, z } from 'h3-zod'
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
const { slug } = await useValidatedParams(event, { const { slug } = await useValidatedParams(event, {
slug: z.string() slug: z.string(),
}) })
return useDB().update(tables.posts) return useDB().update(tables.posts)
.set({ .set({
likes: sql`${tables.posts.likes} likes: sql`${tables.posts.likes}
+ 1` + 1`,
}) })
.where(eq(tables.posts.slug, slug)) .where(eq(tables.posts.slug, slug))
}) })

View File

@@ -10,9 +10,9 @@ export default defineCachedEventHandler(async (event) => {
coding, coding,
editors, editors,
os, os,
languages languages,
} }
}, { }, {
maxAge: 24 * 60 * 60, maxAge: 24 * 60 * 60,
name: 'wakatime' name: 'wakatime',
}) })

View File

@@ -5,5 +5,5 @@ export const posts = sqliteTable('posts', {
slug: text('slug').primaryKey(), slug: text('slug').primaryKey(),
likes: integer('likes').default(0), likes: integer('likes').default(0),
views: integer('views').default(0), views: integer('views').default(0),
createdAt: text('created_at').default(sql`(CURRENT_DATE)`) createdAt: text('created_at').default(sql`(CURRENT_DATE)`),
}) })

View File

@@ -2,7 +2,8 @@ import { consola } from 'consola'
import { migrate } from 'drizzle-orm/d1/migrator' import { migrate } from 'drizzle-orm/d1/migrator'
export default defineNitroPlugin(async () => { export default defineNitroPlugin(async () => {
if (!import.meta.dev) return if (!import.meta.dev)
return
onHubReady(async () => { onHubReady(async () => {
await migrate(useDB(), { migrationsFolder: 'server/database/migrations' }) await migrate(useDB(), { migrationsFolder: 'server/database/migrations' })

View File

@@ -14,24 +14,24 @@ export default <Partial<Config>>{
'./Error.{js,ts,vue}', './Error.{js,ts,vue}',
'./error.{js,ts,vue}', './error.{js,ts,vue}',
'./app.config.{js,ts}', './app.config.{js,ts}',
'content/**/*.md' 'content/**/*.md',
], ],
theme: { theme: {
extend: { extend: {
animation: { animation: {
wave: 'wave 3s infinite' wave: 'wave 3s infinite',
}, },
keyframes: { keyframes: {
wave: { wave: {
'0%, 50%, 100%': { '0%, 50%, 100%': {
transform: 'rotate(-12deg)' transform: 'rotate(-12deg)',
}, },
'25%, 75%': { '25%, 75%': {
transform: 'rotate(12deg) scale(1.5)' transform: 'rotate(12deg) scale(1.5)',
} },
} },
} },
} },
}, },
plugins: [typography] plugins: [typography],
} }

View File

@@ -43,5 +43,5 @@ export interface Activity {
export const IDEs = [ export const IDEs = [
{ name: 'Visual Studio Code', icon: 'i-logos-visual-studio-code' }, { name: 'Visual Studio Code', icon: 'i-logos-visual-studio-code' },
{ name: 'IntelliJ IDEA Ultimate', icon: 'i-logos-intellij-idea' }, { name: 'IntelliJ IDEA Ultimate', icon: 'i-logos-intellij-idea' },
{ name: 'WebStorm', icon: 'i-logos-webstorm' } { name: 'WebStorm', icon: 'i-logos-webstorm' },
] ]