First Commit Test

This commit is contained in:
2023-04-11 15:08:56 +02:00
commit 4079fade0a
24 changed files with 11503 additions and 0 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[**.{json,js,ts,y{a,}ml}]
indent_style = space
indent_size = 2
[*.md]
indent_style = space
indent_size = 4

11
.eslintignore Normal file
View File

@ -0,0 +1,11 @@
# ignore generate imports
auto-imports.d.ts
components.d.ts
nuxt.d.ts
# nuxt and other artefacts
.nuxt
.output
node_modules
dist
public

30
.eslintrc Normal file
View File

@ -0,0 +1,30 @@
{
"root": true,
"env": {
"browser": true,
"node": true
},
"extends": [
"@nuxtjs/eslint-config-typescript"
],
"overrides": [
{
"files": [
"./server/**/*.ts"
],
"rules": {
"no-console": [
"error",
{
"allow": [
"info",
"warn",
"trace",
"error"
]
}
]
}
}
]
}

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
node_modules
*.log*
.nuxt
.nitro
.cache
.output
.env
dist
*.sqlite

8
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"recommendations": [
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"vue.volar",
"bradlc.vscode-tailwindcss"
]
}

30
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
// Use `eslint` for vue, ts and js
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"[vue]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[js]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[ts]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"eslint.validate": [
"javascript",
"typescript",
"vue"
],
// Tailwind Support, see https://tailwindcss.nuxt.dev/tailwind/editor-support
"tailwindCSS.experimental.configFile": ".nuxt/tailwind.config.cjs",
"files.associations": {
"*.css": "tailwindcss"
},
// Auto-complete `.value` attribute when volar is installed
"volar.autoCompleteRefs": true,
}

52
README.md Normal file
View File

@ -0,0 +1,52 @@
# webadmin3.0-app
This is a [sidebase merino](https://sidebase.io/) app created by running `npm create sidebase@latest`. This project uses the following technologies for a great developer- and user-experience:
- [TypeScript](https://www.typescriptlang.org/)
- [Nuxt 3](https://nuxt.com)
- Prisma ORM
- tRPC 10
- Naive UI
## How to get going?
This is a straight-forward setup with minimal templating and scaffolding. The options you selected during the sidebase CLI setup are all here though. Good places to continue reading are:
- [the First Steps documentation](https://sidebase.io/sidebase/usage)
- [our discord](https://discord.gg/auc8eCeGzx)
Some tasks you should probably do in the beginning are:
- [ ] replace this generic README with a more specific one
- [ ] install the Vue Volar extension
- [ ] enable [Volar takeover mode](https://nuxt.com/docs/getting-started/installation#prerequisites) to ensure a smooth editor setup
- [ ] [install Nuxt 3 devtools](https://github.com/nuxt/devtools#installation) if you want to use them
- [ ] Prisma: Edit your `prisma/prisma.schema` to your liking
- [ ] Prisma: Run `npx prisma db push` to sync the schema to your database & generate the Prisma Client
### Setup
Make sure to install the dependencies:
```bash
npm install
```
### Development Server
Start the development server on http://localhost:3000
```bash
npm run dev
```
### Production
Build the application for production:
```bash
npm run build
```
Locally preview production build:
```bash
npm run preview
```

5
app.vue Normal file
View File

@ -0,0 +1,5 @@
<template>
<div>
<NuxtPage />
</div>
</template>

14
nuxt.config.ts Normal file
View File

@ -0,0 +1,14 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: [
'@huntersofbook/naive-ui-nuxt'
],
build: {
transpile: [
'trpc-nuxt'
]
},
typescript: {
shim: false
}
})

10913
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

31
package.json Normal file
View File

@ -0,0 +1,31 @@
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"lint": "eslint --max-warnings 0 .",
"typecheck": "nuxt typecheck",
"start": "NODE_ENV=production node .output/server/index.mjs"
},
"devDependencies": {
"@huntersofbook/naive-ui-nuxt": "^0.7.1",
"prisma": "^4.11.0",
"@nuxtjs/eslint-config-typescript": "^12.0.0",
"@types/node": "^18.11.18",
"eslint": "^8.33.0",
"nuxt": "^3.2.3",
"typescript": "^4.9.5",
"vue-tsc": "^1.0.24"
},
"dependencies": {
"superjson": "^1.12.2",
"zod": "^3.21.2",
"trpc-nuxt": "^0.7.0",
"@trpc/client": "^10.12.0",
"@trpc/server": "^10.12.0",
"@prisma/client": "^4.11.0"
}
}

195
pages/index.vue Normal file
View File

@ -0,0 +1,195 @@
<template>
<div class="main-container">
<div class="heading">
<h1 class="heading__title">
Welcome to your new <span class="gradient__text">sidebase</span> app!
</h1>
<p class="heading__credits">
Read our documentation <a href="https://sidebase.io/sidebase/welcome" target="_blank">here</a>.
Get started in no time with the following amazing modules:
</p>
</div>
<div class="cards">
<div class="card prisma__card">
<div class="card__body">
<h2 class="card__title">
Prisma ORM
</h2>
<p>
Prisma unlocks a new level of developer experience when working with databases thanks to its intuitive data model, automated migrations, type-safety & auto-completion.
</p>
</div>
<p class="card__action">
<a class="card__link" href="https://sidebase.io/sidebase/components/prisma" target="_blank">
TEST
</a>
<a class="card__link" href="/prisma" target="_blank">
See example
</a>
</p>
</div>
<div class="card trpc__card">
<div class="card__body">
<h2 class="card__title">
tRPC
</h2>
<p>
tRPC allows you to easily build & consume fully typesafe APIs without schemas or code generation.
</p>
</div>
<p class="card__action">
<a class="card__link" href="https://sidebase.io/sidebase/components/trpc" target="_blank">
Read documentation
</a>
<a class="card__link" href="/trpc" target="_blank">
See example
</a>
</p>
</div>
<div class="card naiveui__card">
<div class="card__body">
<h2 class="card__title">
NaiveUI
</h2>
<p>
A Vue 3 Component Library. Complete, Customizable, Uses TypeScript, Fast.
</p>
</div>
<p class="card__action">
<a class="card__link" href="https://www.naiveui.com/en-US/os-theme" target="_blank">
Read documentation
</a>
</p>
</div>
</div>
</div>
</template>
<style scoped>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background-color: #eefbfc;
color: #484848;
}
.main-container {
max-width: 45vw;
margin: auto;
padding-top: 60px;
}
/* HEADING */
.heading {
text-align: center;
}
.heading__title {
font-weight: 600;
font-size: 40px;
}
.gradient__text {
background: linear-gradient(to right, #7bceb6 10%, #12a87b 40%, #0FCF97 60%, #7bceb6 90%);
background-size: 200% auto;
color: #000;
background-clip: text;
text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: shine 1s linear infinite;
}
@keyframes shine {
to {
background-position: 200% center;
}
}
.heading__credits {
color: #888888;
font-size: 25px;
transition: all 0.5s;
}
.heading__credits a {
text-decoration: underline;
}
/* CARDS */
.cards {
display: grid;
gap: 20px;
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 30px;
}
.card {
padding: 20px;
width: 100%;
min-height: 200px;
display: grid;
grid-template-rows: 20px 50px 1fr 50px;
border-radius: 10px;
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.25);
transition: all 0.2s;
cursor: default;
}
.card:hover {
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.4);
transform: scale(1.01);
}
.card__link {
position: relative;
text-decoration: underline;
color: rgba(255, 255, 255, 0.9);
}
.card__title {
font-weight: 400;
color: #ffffff;
font-size: 30px;
}
.card__body {
grid-row: 2/4;
}
.card__body p {
color: #ffffff;
}
.card__action {
grid-row: 5/6;
align-self: center;
display: flex;
gap: 20px
}
/* RESPONSIVE */
@media (max-width: 1600px) {
.main-container {
max-width: 100vw;
padding: 50px;
}
.cards {
justify-content: center;
grid-template-columns: repeat(1, minmax(0, 1fr));
}
}
.prisma__card { background: radial-gradient(#3fbafe, #5A67D8FF); }
.trpc__card { background: radial-gradient(#a07ccf, #926dc2); }
.naiveui__card { background: radial-gradient(#ad6434, #995020); }
</style>

9
pages/prisma.vue Normal file
View File

@ -0,0 +1,9 @@
<script setup lang="ts">
const { data: examples } = useFetch('/api/examples')
</script>
<template>
<div>
Prisma ORM Data from the database, received {{ examples?.length || 0 }} records: <pre>{{ examples }}</pre>
</div>
</template>

12
pages/trpc.vue Normal file
View File

@ -0,0 +1,12 @@
<script setup lang="ts">
const { $client } = useNuxtApp()
const hello = await $client.hello.useQuery({ text: 'client' })
</script>
<template>
<div>
<!-- As `superjson` is already pre-configured, we can use `time` as a `Date` object without further deserialization 🎉 -->
tRPC Data: "{{ hello.data.value?.greeting }}" send at "{{ hello.data.value?.time.toLocaleDateString('en-EN') }}".
</div>
</template>

24
plugins/trpcClient.ts Normal file
View File

@ -0,0 +1,24 @@
import { createTRPCNuxtClient, httpBatchLink } from 'trpc-nuxt/client'
import superjson from 'superjson'
import type { AppRouter } from '~/server/trpc/routers'
export default defineNuxtPlugin(() => {
/**
* createTRPCNuxtClient adds a `useQuery` composable
* built on top of `useAsyncData`.
*/
const client = createTRPCNuxtClient<AppRouter>({
transformer: superjson,
links: [
httpBatchLink({
url: '/api/trpc'
})
]
})
return {
provide: {
client
}
}
})

19
prisma/schema.prisma Normal file
View File

@ -0,0 +1,19 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
// NOTE: You probably want to change this to another database later on
provider = "sqlite"
// This value is read from the .env file.
url = env("DATABASE_URL")
}
model Example {
id String @id @default(uuid())
details String
}

23
prisma/utils.ts Normal file
View File

@ -0,0 +1,23 @@
import { execSync } from 'child_process'
/**
* Helper to reset the database via a programmatic prisma invocation. Helpful to add to `beforeEach` or `beforeAll` of your testing setup.
*
* WARNING: Never run this in production.
*
* Taken from https://github.com/prisma/prisma/issues/13549#issuecomment-1144883246
*
* @param databaseUrl Connection URL to database. Inferred from `process.env.DATABASE_URL` if not provided
*/
export const resetDatabase = (databaseUrl?: string) => {
const url = databaseUrl || process.env.DATABASE_URL
if (!url) {
throw new Error('Cannot reset database - connection string could not be inferred.')
}
if (process.env.NODE_ENV === 'production') {
throw new Error('This utility should not be called in production. It is meant for testing and development')
}
execSync(`cd ${process.cwd()} && DATABASE_URL=${url} npx prisma db push --force-reset`, { stdio: 'inherit' })
}

View File

@ -0,0 +1,13 @@
/**
* Fetch all `examples` from the database. Run `npx prisma db push` at least once for this to work.
*
* If you are using `tRPC` you can access the prisma-client by adding it to the context:
* ```ts
* export async function createContext(event: H3Event) {
* return { prisma: event.context.prisma }
* }
*
* export type Context = inferAsyncReturnType<typeof createContext>
* ```
*/
export default defineEventHandler(event => event.context.prisma.example.findMany())

View File

@ -0,0 +1,9 @@
import { createNuxtApiHandler } from 'trpc-nuxt'
import { appRouter } from '~/server/trpc/routers'
import { createContext } from '~/server/trpc/context'
// export API handler
export default createNuxtApiHandler({
router: appRouter,
createContext
})

View File

@ -0,0 +1,16 @@
import { PrismaClient } from '@prisma/client'
let prisma: PrismaClient
declare module 'h3' {
interface H3EventContext {
prisma: PrismaClient
}
}
export default eventHandler((event) => {
if (!prisma) {
prisma = new PrismaClient()
}
event.context.prisma = prisma
})

18
server/trpc/context.ts Normal file
View File

@ -0,0 +1,18 @@
import { inferAsyncReturnType } from '@trpc/server'
import type { H3Event } from 'h3'
/**
* Creates context for an incoming request
* @link https://trpc.io/docs/context
*/
export function createContext (_event: H3Event) {
/**
* Add any trpc-request context here. E.g., you could add `prisma` like this (if you've added it via sidebase):
* ```ts
* return { prisma: _event.context.prisma }
* ```
*/
return {}
}
export type Context = inferAsyncReturnType<typeof createContext>

View File

@ -0,0 +1,20 @@
import { z } from 'zod'
import { publicProcedure, router } from '../trpc'
export const appRouter = router({
hello: publicProcedure
.input(
z.object({
text: z.string().nullish()
})
)
.query(({ input }) => {
return {
greeting: `hello ${input?.text ?? 'world'}`,
time: new Date()
}
})
})
// export type definition of API
export type AppRouter = typeof appRouter

23
server/trpc/trpc.ts Normal file
View File

@ -0,0 +1,23 @@
/**
* This is your entry point to setup the root configuration for tRPC on the server.
* - `initTRPC` should only be used once per app.
* - We export only the functionality that we use so we can enforce which base procedures should be used
*
* Learn how to create protected base procedures and other things below:
* @see https://trpc.io/docs/v10/router
* @see https://trpc.io/docs/v10/procedures
*/
import { initTRPC } from '@trpc/server'
import superjson from 'superjson'
import { Context } from '~/server/trpc/context'
const t = initTRPC.context<Context>().create({
transformer: superjson
})
/**
* Unprotected procedure
**/
export const publicProcedure = t.procedure
export const router = t.router
export const middleware = t.middleware

4
tsconfig.json Normal file
View File

@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}