mirror of
https://github.com/ArthurDanjou/website.git
synced 2026-01-14 12:14:42 +01:00
use h3 instead of trpc
This commit is contained in:
@@ -1,24 +1,19 @@
|
||||
export default defineNuxtConfig({
|
||||
srcDir: 'src',
|
||||
|
||||
build: {
|
||||
transpile: ['trpc-nuxt'],
|
||||
},
|
||||
|
||||
css: [
|
||||
'@/assets/css/main.scss',
|
||||
],
|
||||
|
||||
modules: [
|
||||
'@nuxt/ui',
|
||||
'nuxt-auth-utils',
|
||||
'@nuxt/image',
|
||||
'@nuxthq/studio',
|
||||
'@nuxt/content',
|
||||
'@nuxt/ui',
|
||||
'@pinia/nuxt',
|
||||
'@pinia-plugin-persistedstate/nuxt',
|
||||
'@nuxt/devtools',
|
||||
'@vueuse/nuxt',
|
||||
'nuxt-icon',
|
||||
],
|
||||
|
||||
colorMode: {
|
||||
|
||||
38
package.json
38
package.json
@@ -13,38 +13,32 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/content": "2.9.0",
|
||||
"@nuxt/image": "1.0.0",
|
||||
"@nuxt/ui": "^2.10.0",
|
||||
"@nuxt/image": "1.1.0",
|
||||
"@nuxt/ui": "2.11.0",
|
||||
"@pinia/nuxt": "0.5.1",
|
||||
"@prisma/client": "^5.6.0",
|
||||
"@tresjs/nuxt": "^1.2.2",
|
||||
"@trpc/client": "10.43.3",
|
||||
"@trpc/server": "10.43.3",
|
||||
"@prisma/client": "5.7.0",
|
||||
"@vercel/analytics": "1.1.1",
|
||||
"@vueuse/motion": "2.0.0",
|
||||
"pinia": "2.1.7",
|
||||
"postcss-custom-properties": "13.3.2",
|
||||
"sass": "1.69.5",
|
||||
"superjson": "2.2.1",
|
||||
"tailwindcss": "3.3.5",
|
||||
"three": "^0.158.0",
|
||||
"trpc-nuxt": "0.10.12",
|
||||
"zod": "3.22.4"
|
||||
"tailwindcss": "3.3.6",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "1.1.0",
|
||||
"@iconify/json": "2.2.140",
|
||||
"@nuxt/devtools": "1.0.1",
|
||||
"@nuxthq/studio": "1.0.3",
|
||||
"@antfu/eslint-config": "2.4.2",
|
||||
"@iconify/json": "2.2.153",
|
||||
"@nuxthq/studio": "1.0.5",
|
||||
"@pinia-plugin-persistedstate/nuxt": "1.2.0",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/node": "20.9.0",
|
||||
"@vueuse/core": "10.6.0",
|
||||
"@vueuse/nuxt": "10.6.0",
|
||||
"eslint": "8.53.0",
|
||||
"nuxt": "3.8.1",
|
||||
"nuxt-icon": "0.5.0",
|
||||
"prisma": "^5.6.0",
|
||||
"typescript": "5.2.2"
|
||||
"@types/node": "20.10.4",
|
||||
"@vueuse/core": "10.7.0",
|
||||
"@vueuse/nuxt": "10.7.0",
|
||||
"eslint": "8.55.0",
|
||||
"nuxt": "3.8.2",
|
||||
"nuxt-auth-utils": "^0.0.10",
|
||||
"prisma": "5.7.0",
|
||||
"typescript": "5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ model Category {
|
||||
createdAt DateTime @default(now())
|
||||
slug String
|
||||
name String
|
||||
type CategoryType
|
||||
bookmarks CategoriesOnBookMarks[]
|
||||
talents CategoriesOnTalents[]
|
||||
}
|
||||
|
||||
@@ -56,26 +54,6 @@ model CategoriesOnTalents {
|
||||
@@index([categoryId])
|
||||
}
|
||||
|
||||
model BookMark {
|
||||
id Int @id @default(autoincrement())
|
||||
createdAd DateTime @default(now())
|
||||
name String
|
||||
description String
|
||||
link String
|
||||
CategoriesOnBookMarks CategoriesOnBookMarks[]
|
||||
}
|
||||
|
||||
model CategoriesOnBookMarks {
|
||||
bookmarkId Int
|
||||
categoryId Int
|
||||
bookmark BookMark @relation(fields: [bookmarkId], references: [id])
|
||||
category Category @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@id([bookmarkId, categoryId])
|
||||
@@index([bookmarkId])
|
||||
@@index([categoryId])
|
||||
}
|
||||
|
||||
model Post {
|
||||
id Int @id @default(autoincrement())
|
||||
slug String @unique
|
||||
@@ -84,6 +62,14 @@ model Post {
|
||||
likes Int @default(0)
|
||||
}
|
||||
|
||||
model Suggestion {
|
||||
id Int @id @default(autoincrement())
|
||||
author String @unique
|
||||
content String
|
||||
added Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Form {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
@@ -91,8 +77,3 @@ model Form {
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
enum CategoryType {
|
||||
TALENT
|
||||
BOOKMARK
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
const { $trpc } = useNuxtApp()
|
||||
const announce = await $trpc.announcement.get.query()
|
||||
const { data: announce } = await useFetch('/api/announcement')
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
function getColor() {
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
navigation: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="z-30 sticky top-0 left-0 flex justify-center w-full">
|
||||
<div class="w-full px-4 sm:px-6 lg:px-8 sm:mx-8 max-w-7xl py-4 flex justify-between bg-white dark:bg-zinc-900 border-b border-zinc-100 dark:border-zinc-300/10">
|
||||
<div class="w-full px-4 sm:px-6 lg:px-8 sm:mx-8 max-w-7xl py-4 flex justify-between items-center bg-white dark:bg-zinc-900 border-b border-zinc-100 dark:border-zinc-300/10">
|
||||
<ClientOnly>
|
||||
<Logo />
|
||||
<NavBar v-if="navigation" />
|
||||
<div class="flex gap-2">
|
||||
<NavBar />
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="flex items-center rounded-md p-1 gap-1 relative bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
|
||||
<ColorPicker />
|
||||
<ColorModeButton />
|
||||
</div>
|
||||
<MobileNavBar v-if="navigation" />
|
||||
<MobileNavBar />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
|
||||
@@ -54,7 +54,7 @@ function isRoute(path: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="md:hidden">
|
||||
<div class="lg:hidden">
|
||||
<div class="p-1 rounded-md bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
|
||||
<UButton
|
||||
variant="ghost"
|
||||
@@ -69,7 +69,7 @@ function isRoute(path: string) {
|
||||
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<div>Logo</div>
|
||||
<Logo />
|
||||
<UButton
|
||||
size="md"
|
||||
icon="i-ic-round-close"
|
||||
|
||||
@@ -6,15 +6,15 @@ const items = [
|
||||
to: '/talents',
|
||||
icon: 'i-ph-users-bold',
|
||||
}, {
|
||||
label: 'Bookmarks',
|
||||
to: '/bookmarks',
|
||||
icon: 'i-ph-bookmark-simple-bold',
|
||||
label: 'Guestbook',
|
||||
to: '/guestbook',
|
||||
icon: 'i-material-symbols-book-2-outline',
|
||||
}],
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="hidden md:block z-50">
|
||||
<nav class="hidden lg:block z-50">
|
||||
<div class="flex items-center h-10 rounded-md p-1 gap-1 relative bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
|
||||
<UButton to="/" size="sm" variant="ghost" color="white" :class="{ 'link-active': route.path === '/' }">
|
||||
Home
|
||||
|
||||
@@ -15,8 +15,8 @@ const isLight = computed(() => $colorMode.value === 'light')
|
||||
class="flex items-center gap-2 rounded-md px-2 py-3 duration-300 md:hover:bg-gray-100 md:dark:hover:bg-neutral-800"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<Icon v-if="isLight" :name="skill.icon.light ? skill.icon.light : skill.icon" size="20" />
|
||||
<Icon v-else :name="skill.icon.dark ? skill.icon.dark : skill.icon" size="20" />
|
||||
<UIcon v-if="isLight" :name="skill.icon.light ? skill.icon.light : skill.icon" size="20" dynamic />
|
||||
<UIcon v-else :name="skill.icon.dark ? skill.icon.dark : skill.icon" size="20" dynamic />
|
||||
</div>
|
||||
<span class="text-sm text-subtitle">{{ skill.name }}</span>
|
||||
</li>
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
export async function usePost(slug: string) {
|
||||
const { $trpc } = useNuxtApp()
|
||||
|
||||
const {
|
||||
data: post,
|
||||
refresh: refreshPost,
|
||||
} = await useAsyncData(`blog:post-db:${slug}`, async () => await $trpc.post.createOrUpdate.mutate({
|
||||
slug,
|
||||
}))
|
||||
} = useFetch('/api/article', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
slug,
|
||||
},
|
||||
})
|
||||
|
||||
const likes = ref(post.value!.likes)
|
||||
const likes = ref(post.value?.likes)
|
||||
const like = async () => {
|
||||
const data = await $trpc.post.like.mutate({ slug })
|
||||
likes.value = data.likes
|
||||
const { data } = await useFetch('/api/like', { method: 'PUT' })
|
||||
likes.value = data
|
||||
}
|
||||
|
||||
const views = ref(post.value!.views)
|
||||
const view = async () => {
|
||||
const data = await $trpc.post.view.mutate({ slug })
|
||||
views.value = data.views
|
||||
const { data } = await useFetch('/api/view', { method: 'PUT' })
|
||||
likes.value = data
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { useTalentsStore } from '~/store/talents'
|
||||
|
||||
export async function useTalents() {
|
||||
const { $trpc } = useNuxtApp()
|
||||
const { setCategory, setFavorite, getCategory, isFavorite } = useTalentsStore()
|
||||
|
||||
const {
|
||||
data: talents,
|
||||
refresh: refreshTalents,
|
||||
pending,
|
||||
} = await useAsyncData('talents:talents', async () => await $trpc.talents.getTalents.query({ favorite: isFavorite.value, category: getCategory.value }))
|
||||
|
||||
async function switchCategory(category: string) {
|
||||
setCategory(category)
|
||||
await refreshTalents()
|
||||
}
|
||||
|
||||
async function toggleFavorite() {
|
||||
setFavorite()
|
||||
await refreshTalents()
|
||||
}
|
||||
|
||||
function isCategory(category: string) {
|
||||
return getCategory.value === category
|
||||
}
|
||||
|
||||
const {
|
||||
data: getCategories,
|
||||
} = await $trpc.talents.getCategories.useQuery()
|
||||
|
||||
return {
|
||||
talents,
|
||||
getCategories,
|
||||
isFavorite,
|
||||
switchCategory,
|
||||
toggleFavorite,
|
||||
pending,
|
||||
isCategory,
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
export default defineNuxtRouteMiddleware(async (to) => {
|
||||
const isMaintenance = ref<boolean>(true)
|
||||
const { $trpc } = useNuxtApp()
|
||||
|
||||
try {
|
||||
isMaintenance.value = await $trpc.maintenance.is.query()
|
||||
await $fetch('/api/maintenance').then((maintenance: any) => {
|
||||
isMaintenance.value = maintenance.enabled
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
return navigateTo('/maintenance')
|
||||
|
||||
@@ -7,8 +7,7 @@ useHead({
|
||||
title: 'Site under maintenance • Arthur Danjou',
|
||||
})
|
||||
|
||||
const { $trpc } = useNuxtApp()
|
||||
const maintenance = await $trpc.maintenance.get.query()
|
||||
const { data: maintenance } = await useFetch('/api/maintenance')
|
||||
const format = 'DD MMMM YYYY, HH:mm'
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
@@ -47,13 +46,13 @@ const socials = [
|
||||
<h1 class="text-4xl md:text-7xl font-bold">
|
||||
The website is under maintenance
|
||||
</h1>
|
||||
<div v-if="maintenance">
|
||||
<div v-if="maintenance && maintenance.maintenance">
|
||||
<p :class="getColor" class="font-bold mb-8 text-xl">
|
||||
{{ maintenance.reason }}
|
||||
{{ maintenance.maintenance.reason }}
|
||||
</p>
|
||||
<div>
|
||||
<p class="text-subtitle italic">
|
||||
Maintenance planned from {{ useDateFormat(maintenance.beginAt, format).value }} to {{ useDateFormat(maintenance.endAt, format).value }}
|
||||
Maintenance planned from {{ useDateFormat(maintenance.maintenance.beginAt, format).value }} to {{ useDateFormat(maintenance.maintenance.endAt, format).value }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,32 @@
|
||||
<script lang="ts" setup>
|
||||
import { useTalentsStore } from '~/store/talents'
|
||||
|
||||
useHead({
|
||||
title: 'Discover new talents • Arthur Danjou',
|
||||
})
|
||||
|
||||
const categories = ref<Array<{ label: string; slug: string }>>([{ label: 'All', slug: 'all' }])
|
||||
const { getCategories, talents, isFavorite, toggleFavorite, switchCategory, pending, isCategory } = await useTalents()
|
||||
const { getCategory, setCategory, isFavorite, toggleFavorite } = useTalentsStore()
|
||||
|
||||
const {
|
||||
data: talents,
|
||||
pending,
|
||||
} = await useFetch('/api/talents', {
|
||||
method: 'get',
|
||||
query: {
|
||||
favorite: isFavorite,
|
||||
category: getCategory,
|
||||
},
|
||||
watch: [isFavorite, getCategory]
|
||||
})
|
||||
|
||||
function isCategory(category: string) {
|
||||
return getCategory.value === category
|
||||
}
|
||||
|
||||
const {
|
||||
data: getCategories,
|
||||
} = await useFetch('/api/categories', { method: 'GET' })
|
||||
|
||||
getCategories.value?.forEach(category => categories.value.push({ label: category.name, slug: category.slug }))
|
||||
|
||||
@@ -28,6 +50,7 @@ function getColor() {
|
||||
<div class="mb-6">
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<UIcon name="i-ph-circle-wavy-question-bold" class="text-subtitle text-xl" />
|
||||
<!-- TODO: use suggestions -->
|
||||
<h1 class="text-lg font-bold">
|
||||
Want to be here ?
|
||||
</h1>
|
||||
@@ -43,21 +66,14 @@ function getColor() {
|
||||
<div v-if="getCategories" class="flex gap-2 w-full items-center justify-between pb-2 border-b border-zinc-100 dark:border-zinc-700/40 mb-4">
|
||||
<div class="flex gap-2 overflow-x-scroll sm:overflow-x-hidden bg-gray-100 dark:bg-gray-800 rounded-lg p-1 relative">
|
||||
<div
|
||||
class="relative px-3 py-1 text-sm font-medium rounded-md h-8 text-gray-500 dark:text-gray-400 min-w-fit flex items-center justify-center w-full focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors duration-200 ease-out cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 hover:text-black dark:hover:text-white"
|
||||
:class="{ 'text-gray-900 dark:text-white relative !bg-white dark:!bg-stone-900 rounded-md shadow-sm': isCategory('all') }"
|
||||
@click.prevent="switchCategory('all')"
|
||||
>
|
||||
All
|
||||
</div>
|
||||
<div
|
||||
v-for="category in getCategories"
|
||||
v-for="category in categories"
|
||||
:key="category.slug"
|
||||
class="relative px-3 py-1 text-sm font-medium rounded-md h-8 text-gray-500 dark:text-gray-400 min-w-fit flex items-center justify-center w-full focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors duration-200 ease-out cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 hover:text-black dark:hover:text-white"
|
||||
:class="{ 'text-gray-900 dark:text-white relative !bg-white dark:!bg-stone-900 rounded-md shadow-sm': isCategory(category.slug) }"
|
||||
@click.prevent="switchCategory(category.slug)"
|
||||
@click.prevent="setCategory(category.slug)"
|
||||
>
|
||||
<p class="w-full">
|
||||
{{ category.name }}
|
||||
{{ category.label }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -31,7 +31,7 @@ const { data: projects } = await useProjects()
|
||||
class="group relative flex flex-col justify-between"
|
||||
>
|
||||
<div class="relative z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white shadow-md shadow-zinc-800/5 ring-1 ring-zinc-900/5 dark:border dark:border-zinc-700/50 dark:bg-zinc-800 dark:ring-0">
|
||||
<Icon :name="project.icon" size="24" />
|
||||
<UIcon :name="project.icon" size="24" dynamic />
|
||||
</div>
|
||||
<h2 class="mt-6 text-base font-semibold text-zinc-800 dark:text-zinc-100">
|
||||
<div class="absolute -inset-y-6 -inset-x-4 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 dark:bg-zinc-800/50 sm:-inset-x-6 sm:rounded-2xl" />
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { loggerLink } from '@trpc/client'
|
||||
import SuperJSON from 'superjson'
|
||||
import { createTRPCNuxtClient, httpBatchLink } from 'trpc-nuxt/client'
|
||||
import type { AppRouter } from '~/server/trpc/routers'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const trpc = createTRPCNuxtClient<AppRouter>({
|
||||
transformer: SuperJSON,
|
||||
links: [
|
||||
loggerLink({
|
||||
enabled: opts =>
|
||||
process.env.NODE_ENV === 'development'
|
||||
|| (opts.direction === 'down' && opts.result instanceof Error),
|
||||
}),
|
||||
httpBatchLink({
|
||||
url: '/api/trpc',
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
return {
|
||||
provide: {
|
||||
trpc,
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
import { createNuxtApiHandler } from 'trpc-nuxt'
|
||||
import { createContext } from '~/server/trpc/context'
|
||||
import { appRouter } from '~/server/trpc/routers'
|
||||
|
||||
export default createNuxtApiHandler({
|
||||
createContext,
|
||||
router: appRouter,
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import type { inferAsyncReturnType } from '@trpc/server'
|
||||
import type { H3Event } from 'h3'
|
||||
|
||||
let prisma: PrismaClient | undefined
|
||||
|
||||
export function createContext(_event: H3Event) {
|
||||
if (!prisma) {
|
||||
prisma = new PrismaClient({
|
||||
log: ['warn', 'info', 'error'],
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
prisma,
|
||||
}
|
||||
}
|
||||
|
||||
export type Context = inferAsyncReturnType<typeof createContext>
|
||||
@@ -1,12 +0,0 @@
|
||||
import { publicProcedure, router } from '../trpc'
|
||||
|
||||
export default router({
|
||||
get: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
return await ctx.prisma.announcement.findFirst({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
})
|
||||
}),
|
||||
})
|
||||
@@ -1,14 +0,0 @@
|
||||
import { router } from '../trpc'
|
||||
import announcement from './announcement'
|
||||
import maintenance from './maintenance'
|
||||
import post from './post'
|
||||
import talents from './talents'
|
||||
|
||||
export const appRouter = router({
|
||||
announcement,
|
||||
post,
|
||||
talents,
|
||||
maintenance,
|
||||
})
|
||||
|
||||
export type AppRouter = typeof appRouter
|
||||
@@ -1,29 +0,0 @@
|
||||
import { publicProcedure, router } from '../trpc'
|
||||
|
||||
export default router({
|
||||
get: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
return await ctx.prisma.maintenance.findFirst({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
})
|
||||
}),
|
||||
is: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
const maintenance = await ctx.prisma.maintenance.findFirst({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV === 'development')
|
||||
return false
|
||||
|
||||
const today = new Date()
|
||||
return !!maintenance
|
||||
&& maintenance.enabled
|
||||
&& maintenance.beginAt.getTime() < today.getTime()
|
||||
&& maintenance.endAt.getTime() > today.getTime()
|
||||
}),
|
||||
})
|
||||
@@ -1,68 +0,0 @@
|
||||
import { z } from 'zod'
|
||||
import { publicProcedure, router } from '../trpc'
|
||||
|
||||
const PostSchema = z.object({
|
||||
slug: z.string(),
|
||||
})
|
||||
|
||||
export default router({
|
||||
createOrUpdate: publicProcedure
|
||||
.input(PostSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return await ctx.prisma.post.upsert({
|
||||
where: {
|
||||
slug: input.slug,
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
slug: input.slug,
|
||||
},
|
||||
})
|
||||
}),
|
||||
getTotalViews: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
const views = await ctx.prisma.post.aggregate({
|
||||
_sum: {
|
||||
views: true,
|
||||
},
|
||||
})
|
||||
return views._sum.views || 0
|
||||
}),
|
||||
view: publicProcedure
|
||||
.input(PostSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return await ctx.prisma.post.update({
|
||||
where: {
|
||||
slug: input.slug,
|
||||
},
|
||||
data: {
|
||||
views: {
|
||||
increment: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
getTotalLikes: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
const likes = await ctx.prisma.post.aggregate({
|
||||
_sum: {
|
||||
likes: true,
|
||||
},
|
||||
})
|
||||
return likes._sum.likes || 0
|
||||
}),
|
||||
like: publicProcedure
|
||||
.input(PostSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return await ctx.prisma.post.update({
|
||||
where: {
|
||||
slug: input.slug,
|
||||
},
|
||||
data: {
|
||||
likes: {
|
||||
increment: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
})
|
||||
@@ -1,112 +0,0 @@
|
||||
import { z } from 'zod'
|
||||
import { publicProcedure, router } from '../trpc'
|
||||
|
||||
export default router({
|
||||
getTalents: publicProcedure
|
||||
.input(z.object({
|
||||
favorite: z.boolean(),
|
||||
category: z.union([z.string(), z.literal('all')]),
|
||||
}))
|
||||
.query(async ({ ctx, input }) => {
|
||||
if (input.favorite) {
|
||||
return input.category === 'all'
|
||||
? await ctx.prisma.talent.findMany({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
include: {
|
||||
categories: {
|
||||
include: {
|
||||
talent: true,
|
||||
category: true,
|
||||
},
|
||||
orderBy: {
|
||||
category: {
|
||||
name: 'asc',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
favorite: true,
|
||||
categories: { every: { category: {} } },
|
||||
},
|
||||
})
|
||||
: await ctx.prisma.talent.findMany({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
include: {
|
||||
categories: {
|
||||
include: {
|
||||
talent: true,
|
||||
category: true,
|
||||
},
|
||||
orderBy: {
|
||||
category: {
|
||||
name: 'asc',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
favorite: true,
|
||||
categories: { some: { category: { slug: input.category } } },
|
||||
},
|
||||
})
|
||||
}
|
||||
else {
|
||||
return input.category === 'all'
|
||||
? await ctx.prisma.talent.findMany({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
include: {
|
||||
categories: {
|
||||
include: {
|
||||
talent: true,
|
||||
category: true,
|
||||
},
|
||||
orderBy: {
|
||||
category: {
|
||||
name: 'asc',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
categories: { every: { category: {} } },
|
||||
},
|
||||
})
|
||||
: await ctx.prisma.talent.findMany({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
include: {
|
||||
categories: {
|
||||
include: {
|
||||
talent: true,
|
||||
category: true,
|
||||
},
|
||||
orderBy: {
|
||||
category: {
|
||||
name: 'asc',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
categories: { some: { category: { slug: input.category } } },
|
||||
},
|
||||
})
|
||||
}
|
||||
}),
|
||||
getCategories: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
return await ctx.prisma.category.findMany({
|
||||
where: {
|
||||
type: 'TALENT',
|
||||
},
|
||||
})
|
||||
}),
|
||||
})
|
||||
@@ -1,12 +0,0 @@
|
||||
import { initTRPC } from '@trpc/server'
|
||||
import SuperJSON from 'superjson'
|
||||
import type { Context } from './context'
|
||||
|
||||
const trpc = initTRPC.context<Context>().create({
|
||||
transformer: SuperJSON,
|
||||
})
|
||||
|
||||
export const publicProcedure = trpc.procedure
|
||||
export const router = trpc.router
|
||||
export const middleware = trpc.middleware
|
||||
export const mergeRouters = trpc.mergeRouters
|
||||
@@ -7,21 +7,20 @@ export const useTalentsStore = defineStore(
|
||||
const currentFavorite = ref<boolean>(false)
|
||||
|
||||
const getCategory = computed(() => currentCategory)
|
||||
const isFavorite = computed(() => currentFavorite)
|
||||
|
||||
function setCategory(category: string) {
|
||||
currentCategory.value = category
|
||||
function setCategory(newCategory: string) {
|
||||
currentCategory.value = newCategory
|
||||
}
|
||||
|
||||
function setFavorite() {
|
||||
const isFavorite = computed(() => currentFavorite)
|
||||
function toggleFavorite() {
|
||||
currentFavorite.value = !currentFavorite.value
|
||||
}
|
||||
|
||||
return {
|
||||
getCategory,
|
||||
setCategory,
|
||||
setFavorite,
|
||||
isFavorite,
|
||||
toggleFavorite,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user