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

@@ -71,4 +71,4 @@ NUXT_PUBLIC_I18N_BASE_URL=...
## 📄 License
[MIT](./LICENSE) © Arthur Danjou
[MIT](./LICENSE) © Arthur Danjou

View File

@@ -3,10 +3,10 @@ export default defineAppConfig({
gray: 'neutral',
primary: 'gray',
container: {
constrained: 'max-w-3xl'
constrained: 'max-w-3xl',
},
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>
<Html
:dir="head.htmlAttrs.dir"
@@ -40,18 +52,6 @@
</Html>
</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>
body {
font-family: 'DM Sans', sans-serif;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,13 +4,13 @@ import type { PropType } from 'vue'
defineProps({
href: {
type: String,
default: ''
default: '',
},
target: {
type: String as PropType<'_blank' | '_parent' | '_self' | '_top' | (string & object) | null | undefined>,
default: undefined,
required: false
}
required: false,
},
})
</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>
<h2
:id="id"
@@ -12,12 +21,3 @@
<slot v-else />
</h2>
</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>
<h2
:id="id"
@@ -12,12 +21,3 @@
<slot v-else />
</h2>
</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({
icon: {
type: String,
required: true
}
required: true,
},
})
</script>

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,12 @@
<script lang="ts" setup>
defineProps({
title: {
type: String,
required: true,
},
})
</script>
<template>
<div class="space-y-8">
<UDivider
@@ -9,12 +18,3 @@
</ul>
</div>
</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>
<main class="!max-w-none prose dark:prose-invert">
<ContentDoc :path="`/home/${locale}`" />
</main>
</template>
<script lang="ts" setup>
const { locale } = useI18n()
</script>

View File

@@ -1,14 +1,14 @@
<script setup lang="ts">
const { t } = useI18n({
useScope: 'local'
useScope: 'local',
})
useSeoMeta({
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')

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

View File

@@ -1,23 +1,22 @@
<script setup lang="ts">
const { t, locale } = useI18n({
useScope: 'local'
useScope: 'local',
})
useSeoMeta({
title: 'My Shelf',
description: t('description')
description: t('description'),
})
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', () =>
$fetch(`/api/posts`)
)
$fetch(`/api/posts`))
function getDetails(slug: string) {
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 view = writing.views! > 1 ? t('views.many') : t('views.one')

View File

@@ -5,4 +5,4 @@
"fr": "Probablement l'objet que j'utilise le plus après mon téléphone et mon ordinateur portable. Je les utilise pour tout, de l'écoute de musique à la prise d'appels. Ils sont super pratiques et la qualité sonore est excellente."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'utilise mon iPad pour lire des livres, regarder des films et naviguer sur le web, mais aussi pour prendre des notes et écrire des équations pendant mes cours de mathématiques."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Je n'améliore pas mon téléphone chaque année, mais quand je le fais, je vais pour le meilleur. L'iPhone 14 Pro est le meilleur téléphone sur le marché, et je suis excité de mettre la main dessus."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Mon ordinateur principal pour programmer est un MacBook Pro 13' 2020 avec la puce Apple M1 et 16Go de RAM. J'utilise MacOS Sorona."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'utilise la suite Apple comprenant Mail, Calendar, Notes, Music et Reminders pour mon organisation quotidienne."
},
"category": "software"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'utilise Discord pour discuter et parler avec mes amis et mes clients et discuter avec certains membres de la communauté."
},
"category": "software"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'ai acheté un ordinateur personnalisé pour le jeu. J'ai choisi un Intel Core i5-10400F, avec 16Go DDR4 et ma carte graphique est une RTX 2060. J'utilise Windows 11."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'utilise Google Chrome pour naviguer, l'outil de développement et le marché des extensions."
},
"category": "software"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'utilise la suite JetBrains pour le développement depuis 7 ans. C'est le meilleur IDE pour Java, Python, JavaScript, SQL et plus encore. J'ai utilisé cette suite pour développer et créer ce site web."
},
"category": "ide"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Cette souris de jeu est conçue pour être le compagnon de jeu parfait. Avec un design classique et une disposition simple, cette souris est parfaite pour tout joueur."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Notion est mon outil de prise de notes, de kanban, de wikis et de brouillon tout-en-un."
},
"category": "software"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Raycast est mon lanceur extensible remplaçant Apple Spotlight. Il me permet d'accomplir des tâches, de calculer, de partager des liens communs et bien plus encore grâce aux extensions."
},
"category": "software"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "J'utilise TypeScript, Vue 3 avec Nuxt 3, Nuxt Stack (UI, Hub, Content, Studio) & TailwindCss pour le FrontEnd. Nuxt (alimenté par Nitro) et AdonisJs sont utilisés pour le BackEnd en fonction de la complexité du projet. PostgreSQL est utilisé pour la base de données, Redis pour le caching. Docker est utilisé pour la conteneurisation. Les applications sont déployées sur NuxtHub (alimenté par CloudFlare) ou Vercel."
},
"category": "stack"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Ce clavier TKL est un excellent choix pour les joueurs qui veulent un clavier compact avec de nombreuses fonctionnalités."
},
"category": "hardware"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Mon thème est Catppuccin Macchiato, un thème pastel piloté par la communauté qui vise à être le juste milieu entre les thèmes à faible et à fort contraste. Mes polices principales sont Vercel Geist et JetBrains Mono"
},
"category": "ide"
}
}

View File

@@ -5,4 +5,4 @@
"fr": "Warp est un terminal moderne basé sur Rust réimaginé avec l'IA et des outils collaboratifs pour une meilleure productivité. Je l'adore jusqu'à présent !"
},
"category": "software"
}
}

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
{
"name": "artsite",
"private": true,
"packageManager": "pnpm@9.4.0",
"packageManager": "pnpm@9.5.0",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev --host",
@@ -9,34 +9,34 @@
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"db:generate": "drizzle-kit generate"
},
"dependencies": {
"@iconify/json": "^2.2.225",
"@nuxt/content": "^2.13.1",
"@nuxt/eslint": "^0.3.13",
"@iconify/json": "^2.2.230",
"@nuxt/content": "^2.13.2",
"@nuxt/image": "^1.7.0",
"@nuxt/ui": "^2.17.0",
"@nuxthq/studio": "^2.0.3",
"@nuxthub/core": "^0.7.0",
"@nuxthub/core": "^0.7.1",
"@nuxtjs/google-fonts": "^3.2.0",
"@nuxtjs/i18n": "^8.3.1",
"drizzle-orm": "^0.31.2",
"drizzle-orm": "^0.31.4",
"h3-zod": "^0.5.3",
"nuxt": "^3.12.3",
"nuxt": "^3.12.4",
"zod": "^3.23.8"
},
"devDependencies": {
"@antfu/eslint-config": "^2.23.2",
"@nuxt/devtools": "^1.3.9",
"@nuxt/eslint-config": "^0.3.13",
"@nuxt/ui": "^2.17.0",
"@types/node": "^20.14.10",
"@types/node": "^20.14.12",
"@vueuse/core": "^10.11.0",
"@vueuse/nuxt": "^10.11.0",
"drizzle-kit": "^0.22.8",
"eslint": "^9.6.0",
"typescript": "^5.5.3",
"vue-tsc": "^2.0.26",
"wrangler": "^3.63.1"
"eslint": "^9.7.0",
"typescript": "^5.5.4",
"vue-tsc": "^2.0.28",
"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) => {
const { slug } = await useValidatedParams(event, {
slug: z.string()
slug: z.string(),
})
return useDB().insert(tables.posts).values({
slug
slug,
}).onConflictDoUpdate({
target: tables.posts.slug,
set: {
slug,
views: sql`${tables.posts.views}
+ 1`
}
+ 1`,
},
}).returning().get()
})

View File

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

View File

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

View File

@@ -110,4 +110,4 @@
"internal": {
"indexes": {}
}
}
}

View File

@@ -54,4 +54,4 @@
"internal": {
"indexes": {}
}
}
}

View File

@@ -17,4 +17,4 @@
"breakpoints": true
}
]
}
}

View File

@@ -5,5 +5,5 @@ export const posts = sqliteTable('posts', {
slug: text('slug').primaryKey(),
likes: integer('likes').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'
export default defineNitroPlugin(async () => {
if (!import.meta.dev) return
if (!import.meta.dev)
return
onHubReady(async () => {
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}',
'./app.config.{js,ts}',
'content/**/*.md'
'content/**/*.md',
],
theme: {
extend: {
animation: {
wave: 'wave 3s infinite'
wave: 'wave 3s infinite',
},
keyframes: {
wave: {
'0%, 50%, 100%': {
transform: 'rotate(-12deg)'
transform: 'rotate(-12deg)',
},
'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 = [
{ name: 'Visual Studio Code', icon: 'i-logos-visual-studio-code' },
{ name: 'IntelliJ IDEA Ultimate', icon: 'i-logos-intellij-idea' },
{ name: 'WebStorm', icon: 'i-logos-webstorm' }
{ name: 'WebStorm', icon: 'i-logos-webstorm' },
]