First Commit Test
This commit is contained in:
15
.editorconfig
Normal file
15
.editorconfig
Normal 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
11
.eslintignore
Normal 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
30
.eslintrc
Normal 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
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
node_modules
|
||||
*.log*
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
.output
|
||||
.env
|
||||
dist
|
||||
*.sqlite
|
||||
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"editorconfig.editorconfig",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"vue.volar",
|
||||
"bradlc.vscode-tailwindcss"
|
||||
]
|
||||
}
|
||||
30
.vscode/settings.json
vendored
Normal file
30
.vscode/settings.json
vendored
Normal 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
52
README.md
Normal 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
|
||||
```
|
||||
14
nuxt.config.ts
Normal file
14
nuxt.config.ts
Normal 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
10913
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
package.json
Normal file
31
package.json
Normal 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
195
pages/index.vue
Normal 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
9
pages/prisma.vue
Normal 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
12
pages/trpc.vue
Normal 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
24
plugins/trpcClient.ts
Normal 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
19
prisma/schema.prisma
Normal 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
23
prisma/utils.ts
Normal 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' })
|
||||
}
|
||||
13
server/api/examples.get.ts
Normal file
13
server/api/examples.get.ts
Normal 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())
|
||||
9
server/api/trpc/[trpc].ts
Normal file
9
server/api/trpc/[trpc].ts
Normal 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
|
||||
})
|
||||
16
server/middleware/0.prisma.ts
Normal file
16
server/middleware/0.prisma.ts
Normal 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
18
server/trpc/context.ts
Normal 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>
|
||||
20
server/trpc/routers/index.ts
Normal file
20
server/trpc/routers/index.ts
Normal 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
23
server/trpc/trpc.ts
Normal 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
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
Reference in New Issue
Block a user