├── .env.example ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── apps ├── server │ ├── .gitignore │ ├── .npmrc │ ├── README.md │ ├── esbuild.build.mjs │ ├── nodemon.json │ ├── package.json │ ├── scripts │ │ ├── rail │ │ │ ├── build.sh │ │ │ ├── replacer │ │ │ └── start.sh │ │ └── win │ │ │ ├── build-win.sh │ │ │ └── dum.exe │ ├── src │ │ ├── collections │ │ │ ├── Categories.ts │ │ │ ├── Customers.ts │ │ │ ├── Posts.ts │ │ │ ├── Tags.ts │ │ │ └── Users.ts │ │ ├── payload-types.ts │ │ ├── payload.config.ts │ │ ├── server.mts │ │ ├── trpc │ │ │ ├── context.mts │ │ │ ├── procedures.mts │ │ │ ├── router.mts │ │ │ └── routes │ │ │ │ └── user.mts │ │ └── web │ │ │ └── handler.mts │ └── tsconfig.json └── web │ ├── .gitignore │ ├── .npmrc │ ├── .vscode │ ├── extensions.json │ └── settings.json │ ├── README.md │ ├── my-preset.ts │ ├── package.json │ ├── src │ ├── additional-svelte-jsx.d.ts │ ├── app.d.ts │ ├── app.html │ ├── hooks.server.ts │ ├── lib │ │ └── trpc │ │ │ └── index.ts │ └── routes │ │ ├── +layout.svelte │ │ └── +page.svelte │ ├── static │ └── favicon.png │ ├── svelte.config.js │ ├── tsconfig.json │ ├── uno.config.ts │ └── vite.config.ts ├── package.json ├── packages ├── dum │ ├── README.md │ ├── bin │ │ └── dum.exe │ └── package.json ├── eslint-config-custom │ ├── index.js │ └── package.json └── replacer │ ├── README.md │ ├── bin │ └── replacer.exe │ └── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── sveltekit-payload.code-workspace └── turbo.json /.env.example: -------------------------------------------------------------------------------- 1 | PUBLIC_PORT="3000" 2 | PORT=3000 3 | MONGO_URL="mongodb://127.0.0.1:27017/amcechealth" 4 | PAYLOAD_SECRET="Sheeshbrah" 5 | PUBLIC_PAYLOAD_SERVER_URL="http://localhost:3000" # for sveltekit, needs to sart with "PUBLIC_" 6 | PAYLOAD_PUBLIC_SERVER_URL="http://localhost:3000" 7 | 8 | # This was inserted by `prisma init`: 9 | # Environment variables declared in this file are automatically made available to Prisma. 10 | # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema 11 | 12 | # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. 13 | # See the documentation for all the connection string options: https://pris.ly/d/connection-strings 14 | 15 | DATABASE_URL="mongodb://localhost:27017/test?directConnection=true&serverSelectionTimeoutMS=2000" 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | build 4 | dist 5 | .svelte-kit 6 | package 7 | .env 8 | .env.* 9 | !.env.example 10 | .yarn 11 | 12 | payload-types.ts 13 | 14 | # Ignore files for PNPM, NPM and YARN 15 | pnpm-lock.yaml 16 | package-lock.json 17 | yarn.lock 18 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // This tells ESLint to load the config from the package `eslint-config-custom` 4 | extends: ["custom"], 5 | }; 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # svelte 12 | .svelte-kit 13 | 14 | # misc 15 | .DS_Store 16 | *.pem 17 | 18 | # debug 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # local env files 24 | .env.local 25 | .env.development.local 26 | .env.test.local 27 | .env.production.local 28 | 29 | # turbo 30 | .turbo 31 | 32 | # mine I added 33 | build 34 | dist 35 | package 36 | .env 37 | .env.* 38 | !.env.example 39 | 40 | # Ignore files for PNPM, NPM and YARN 41 | # pnpm-lock.yaml 42 | # package-lock.json 43 | # yarn.lock 44 | 45 | .yarn/* 46 | !.yarn/releases 47 | !.yarn/plugins -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | build 4 | dist 5 | .svelte-kit 6 | package 7 | .env 8 | .env.* 9 | !.env.example 10 | .yarn 11 | 12 | # Ignore files for PNPM, NPM and YARN 13 | pnpm-lock.yaml 14 | package-lock.json 15 | yarn.lock 16 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "tabWidth": 2, 4 | "arrowParens": "avoid", 5 | "singleQuote": false, 6 | "trailingComma": "es5", 7 | "printWidth": 80, 8 | "plugins": ["prettier-plugin-svelte"], 9 | "pluginSearchDirs": ["."], 10 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["antfu.unocss"] 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Ubogu Haniel 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Svelte-Kit + PayloadCMS + tRPC Turborepo 2 | 3 | This is an custom made Turborepo starter. 4 | 5 | ## What's inside? 6 | 7 | This [Turborepo] includes the following packages/apps: 8 | 9 | ### Apps 10 | 11 | Each app is 100% [TypeScript]. 12 | 13 | - `web`: a [Svelte-kit] web app with [UnoCSS] for styling 14 | - `server`: an [Express] app with [PayloadCMS] and [tRPC] setup 15 | 16 | ### Packages 17 | 18 | - `eslint-config-custom`: `eslint` configurations (includes `eslint-plugin-svelte` and `eslint-config-prettier`) 19 | - `dum`: a scripts runner executable written in [Rust] 20 | - `replacer`: A CLI for replacing strings in files and directories written in [Rust] 21 | 22 | ### Utilities 23 | 24 | This Turborepo has some additional tools already setup for you: 25 | 26 | - [TypeScript] for static type checking 27 | - [ESLint] for code linting 28 | - [Prettier] for code formatting 29 | 30 | ## Getting Started 31 | 32 | This project uses [pnpm]. 33 | 34 | ```sh 35 | npx degit HanielU/turbo-sk-payload-trpc my-project # download the project 36 | 37 | cd my-project # navigate into the project 38 | 39 | pnpm install # install dependencies 40 | ``` 41 | 42 | ### Running the apps 43 | 44 | In the project root and run the following command. 45 | 46 | ```sh 47 | pnpm dev 48 | ``` 49 | 50 | This will run both the Svelte-kit and Payload apps in parallel. 51 | 52 | ## License 53 | 54 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 55 | 56 | 57 | 58 | [turborepo]: https://turbo.build/repo 59 | [eslint]: https://eslint.org 60 | [express]: https://expressjs.com 61 | [fastify]: https://www.fastify.io 62 | [payloadcms]: https://www.payloadcms.com 63 | [prettier]: https://prettier.io 64 | [prisma]: https://www.prisma.io 65 | [svelte-kit]: https://kit.svelte.dev 66 | [unocss]: https://github.com/unocss/unocss 67 | [trpc]: https://trpc.io 68 | [typescript]: https://www.typescriptlang.org 69 | [rust]: https://www.rust-lang.org 70 | [pnpm]: https://pnpm.io 71 | -------------------------------------------------------------------------------- /apps/server/.gitignore: -------------------------------------------------------------------------------- 1 | ### Node ### 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | .pnpm-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # Snowpack dependency directory (https://snowpack.dev/) 47 | web_modules/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Optional stylelint cache 59 | .stylelintcache 60 | 61 | # Microbundle cache 62 | .rpt2_cache/ 63 | .rts2_cache_cjs/ 64 | .rts2_cache_es/ 65 | .rts2_cache_umd/ 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variable files 77 | .env 78 | .env.development.local 79 | .env.test.local 80 | .env.production.local 81 | .env.local 82 | 83 | # parcel-bundler cache (https://parceljs.org/) 84 | .cache 85 | .parcel-cache 86 | 87 | # Next.js build output 88 | .next 89 | out 90 | 91 | # Nuxt.js build / generate output 92 | .nuxt 93 | dist 94 | 95 | # Gatsby files 96 | .cache/ 97 | # Comment in the public line in if your project uses Gatsby and not Next.js 98 | # https://nextjs.org/blog/next-9-1#public-directory-support 99 | # public 100 | 101 | # vuepress build output 102 | .vuepress/dist 103 | 104 | # vuepress v2.x temp and cache directory 105 | .temp 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | ### Node Patch ### 133 | # Serverless Webpack directories 134 | .webpack/ 135 | 136 | # Optional stylelint cache 137 | 138 | # SvelteKit build / generate output 139 | .svelte-kit 140 | 141 | ### VisualStudioCode ### 142 | .vscode/* 143 | !.vscode/settings.json 144 | !.vscode/tasks.json 145 | !.vscode/launch.json 146 | !.vscode/extensions.json 147 | !.vscode/*.code-snippets 148 | 149 | # Local History for Visual Studio Code 150 | .history/ 151 | 152 | # Built Visual Studio Code Extensions 153 | *.vsix 154 | 155 | ### VisualStudioCode Patch ### 156 | # Ignore all local history of files 157 | .history 158 | .ionide 159 | 160 | # Support for Project snippet scope 161 | .vscode/*.code-snippets 162 | 163 | # Ignore code-workspaces 164 | *.code-workspace 165 | 166 | # End of https://www.toptal.com/developers/gitignore/api/node,visualstudiocode 167 | -------------------------------------------------------------------------------- /apps/server/.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /apps/server/README.md: -------------------------------------------------------------------------------- 1 | ## How to Use 2 | 3 | **Note:** Make sure you have a MongoDB instance running on your machine before starting the server. 4 | 5 | ### Development 6 | 7 | ```sh 8 | cd ../../ # Go to the root of the project 9 | pnpm run dev:server # Start the server in development mode 10 | ``` 11 | 12 | ### Production (for Windows) 13 | 14 | ```sh 15 | cd ../../ # Go to the root of the project 16 | pnpm run build:win # Build the server 17 | pnpm run start:server-win # Start the server in production mode 18 | ``` 19 | 20 | ### Production (for Linux) 21 | 22 | ```sh 23 | cd ../../ # Go to the root of the project 24 | pnpm run build:server # Build the server 25 | pnpm run start:server # Start the server in production mode 26 | ``` 27 | 28 | # Note the following! 29 | 30 | In this project, **all non payload related** TypeScript files should end in .mts to indicate that they are esmodules. 31 | 32 | Every payload related file must end in the regular `.ts` extension 33 | 34 | Please make sure to follow this naming convention when adding new TypeScript files to the project. 35 | -------------------------------------------------------------------------------- /apps/server/esbuild.build.mjs: -------------------------------------------------------------------------------- 1 | import * as esbuild from "esbuild"; 2 | import { readdir } from "fs/promises"; 3 | import { resolve } from "path"; 4 | 5 | async function* getFiles(dir) { 6 | const dirents = await readdir(dir, { withFileTypes: true }); 7 | for (const dirent of dirents) { 8 | const res = resolve(dir, dirent.name); 9 | if (dirent.isDirectory()) { 10 | yield* getFiles(res); 11 | } else { 12 | yield res; 13 | } 14 | } 15 | } 16 | 17 | (async () => { 18 | const stack = []; 19 | for await (const f of getFiles("src")) { 20 | stack.push(f); 21 | } 22 | 23 | const mjsEntres = stack.filter( 24 | f => 25 | !f.endsWith("types.ts") && 26 | !f.endsWith("config.ts") && 27 | !f.includes("collections") && 28 | !f.includes("access") && 29 | !f.includes("hooks") && 30 | (f.endsWith(".ts") || f.endsWith(".mts")) 31 | ); 32 | 33 | const cjsEntries = stack.filter( 34 | f => 35 | f.endsWith("config.ts") || 36 | f.includes("collections") || 37 | f.includes("access") || 38 | f.includes("hooks") 39 | ); 40 | 41 | await esbuild.build({ 42 | entryPoints: mjsEntres, 43 | platform: "node", 44 | target: "node16", 45 | outdir: "dist", 46 | tsconfig: "./tsconfig.json", 47 | outExtension: { ".js": ".mjs" }, 48 | }); 49 | 50 | await esbuild.build({ 51 | entryPoints: cjsEntries, 52 | platform: "node", 53 | target: "node16", 54 | outdir: "dist", 55 | tsconfig: "./tsconfig.json", 56 | format: "cjs", 57 | outExtension: { ".js": ".cjs" }, 58 | }); 59 | })(); 60 | -------------------------------------------------------------------------------- /apps/server/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ext": "ts,mts", 3 | "exec": "ts-node src/server.mts", 4 | "watch": "./src" 5 | } 6 | -------------------------------------------------------------------------------- /apps/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/server", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "src/trpc/router.mts", 6 | "license": "MIT", 7 | "type": "module", 8 | "scripts": { 9 | "lint": "prettier --check --ignore-path=../../.prettierignore . && eslint --ignore-path=../../.eslintignore .", 10 | "start": "chmod +x ./scripts/rail/start.sh && ./scripts/rail/start.sh && cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.cjs NODE_ENV=production node dist/server.mjs", 11 | "build": "pnpm copyfiles-f && pnpm build:payload && pnpm build:server", 12 | "build:server": "chmod +x ./scripts/rail/build.sh && ./scripts/rail/build.sh", 13 | "build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build", 14 | "dev": "dum mod-off && cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon", 15 | "start:win": "dum mod-on && cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.cjs NODE_ENV=production node dist/server.mjs", 16 | "build:win": "dum copyfiles-f && dum build:payload && dum build:server-win", 17 | "build:server-win": "chmod +x .\\scripts\\win\\build-win.sh && .\\scripts\\win\\build-win.sh", 18 | "copyclient": "cd dist && rm -rf web && mkdir web && cd .. && copyfiles -u 5 ../web/build/** dist/web", 19 | "copyfiles-f": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/", 20 | "generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types", 21 | "generate:graphQLSchema": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema", 22 | "mod-off": "replacer --file ./package.json \"type\": \"#type\":", 23 | "mod-on": "replacer --file ./package.json \"#type\": \"type\":" 24 | }, 25 | "dependencies": { 26 | "@trpc/client": "^10.29.1", 27 | "@trpc/server": "^10.29.1", 28 | "clsx": "^1.2.1", 29 | "cors": "^2.8.5", 30 | "express": "^4.18.2", 31 | "payload": "^1.9.1", 32 | "superjson": "^1.12.3", 33 | "zod": "^3.21.4" 34 | }, 35 | "devDependencies": { 36 | "@packages/dum": "workspace:*", 37 | "@packages/replacer": "workspace:*", 38 | "@types/cors": "^2.8.13", 39 | "@types/express": "^4.17.17", 40 | "copyfiles": "^2.4.1", 41 | "cross-env": "^7.0.3", 42 | "esbuild": "^0.18.0", 43 | "nodemon": "^2.0.22", 44 | "ts-node": "^10.9.1", 45 | "typescript": "^5.1.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /apps/server/scripts/rail/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | chmod +x ./scripts/rail/replacer 4 | 5 | # prepare for build: 6 | # clean dist 7 | # replace access"; with access.cjs"; in all files in the src directory 8 | # replace s"; with s.cjs"; in payload.config.ts 9 | # replace handler.mjs with handler.js in server.mts 10 | # replace "type": with "#type": in package.json 11 | 12 | rm -rf dist 13 | ./scripts/rail/replacer \ 14 | --dirfile ./src 'access";' 'access.cjs";' \ 15 | --file ./src/payload.config.ts 's";' 's.cjs";' \ 16 | --file ./src/server.mts handler.mjs handler.js \ 17 | --file ./package.json '"type":' '"#type":' # mod-off 18 | node esbuild.build.mjs 19 | -------------------------------------------------------------------------------- /apps/server/scripts/rail/replacer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanielu/sk-trpc-payload/366850259098d2b67ba118db757cc4b6edc761de/apps/server/scripts/rail/replacer -------------------------------------------------------------------------------- /apps/server/scripts/rail/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | chmod +x ./scripts/rail/replacer 4 | ./scripts/rail/replacer --file ./package.json '"#type":' '"type":' # mod-on -------------------------------------------------------------------------------- /apps/server/scripts/win/build-win.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # prepare for build: 4 | # clean dist 5 | # replace access"; with access.cjs"; in all files in the src directory 6 | # replace s"; with s.cjs"; in payload.config.ts 7 | # replace handler.mjs with handler.js in server.mts 8 | # replace "type": with "#type": in package.json 9 | 10 | rm -rf dist 11 | ./scripts/win/dum replacer \ 12 | --dirfile ./src 'access";' 'access.cjs";' \ 13 | --file ./src/payload.config.ts 's";' 's.cjs";' \ 14 | --file ./src/server.mts handler.mjs handler.js \ 15 | --file ./package.json '"type":' '"#type":' # mod-off 16 | node ./esbuild.build.mjs # build 17 | 18 | # -------------------------------------------- 19 | 20 | # prepare for dev: 21 | # replace .cjs"; with "; in all files in the src directory 22 | # replace handler.js with handler.mjs in server.mts 23 | 24 | ./scripts/win/dum replacer \ 25 | --dirfile ./src '.cjs";' '";' \ 26 | --file ./src/server.mts handler.js handler.mjs 27 | -------------------------------------------------------------------------------- /apps/server/scripts/win/dum.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanielu/sk-trpc-payload/366850259098d2b67ba118db757cc4b6edc761de/apps/server/scripts/win/dum.exe -------------------------------------------------------------------------------- /apps/server/src/collections/Categories.ts: -------------------------------------------------------------------------------- 1 | import type { CollectionConfig } from "payload/types"; 2 | 3 | const Categories: CollectionConfig = { 4 | slug: "categories", 5 | admin: { 6 | useAsTitle: "name", 7 | }, 8 | access: { 9 | read: () => true, 10 | }, 11 | fields: [ 12 | { 13 | name: "name", 14 | type: "text", 15 | }, 16 | ], 17 | timestamps: false, 18 | }; 19 | 20 | export default Categories; 21 | -------------------------------------------------------------------------------- /apps/server/src/collections/Customers.ts: -------------------------------------------------------------------------------- 1 | import type { CollectionConfig } from "payload/types"; 2 | 3 | const Customers: CollectionConfig = { 4 | slug: "customers", 5 | auth: true, 6 | fields: [ 7 | { 8 | name: "firstName", 9 | type: "text", 10 | required: true, 11 | }, 12 | { 13 | name: "lastName", 14 | type: "text", 15 | required: true, 16 | }, 17 | { 18 | name: "phoneNumber", 19 | type: "text", 20 | required: false, 21 | }, 22 | { 23 | name: "dateOfBirth", 24 | type: "date", 25 | required: false, 26 | }, 27 | { 28 | name: "gender", 29 | type: "select", 30 | hasMany: true, 31 | options: [ 32 | { 33 | label: "Male", 34 | value: "male", 35 | }, 36 | { 37 | label: "Female", 38 | value: "female", 39 | }, 40 | ], 41 | }, 42 | { 43 | name: "viewPost", 44 | type: "relationship", 45 | relationTo: "posts", 46 | hasMany: true, 47 | }, 48 | { 49 | name: "likes", 50 | type: "relationship", 51 | relationTo: "posts", 52 | hasMany: true, 53 | }, 54 | { 55 | name: "likeCount", 56 | type: "number", 57 | defaultValue: 0, 58 | }, 59 | ], 60 | }; 61 | 62 | export default Customers; 63 | -------------------------------------------------------------------------------- /apps/server/src/collections/Posts.ts: -------------------------------------------------------------------------------- 1 | import type { CollectionConfig } from "payload/types"; 2 | 3 | const Posts: CollectionConfig = { 4 | slug: "posts", 5 | admin: { 6 | defaultColumns: ["title", "author", "category", "tags", "status"], 7 | useAsTitle: "title", 8 | }, 9 | access: { 10 | read: () => true, 11 | }, 12 | fields: [ 13 | { 14 | name: "title", 15 | type: "text", 16 | }, 17 | { 18 | name: "author", 19 | type: "relationship", 20 | relationTo: "users", 21 | }, 22 | { 23 | name: "publishedDate", 24 | type: "date", 25 | }, 26 | { 27 | name: "category", 28 | type: "relationship", 29 | relationTo: "categories", 30 | }, 31 | { 32 | name: "tags", 33 | type: "relationship", 34 | relationTo: "tags", 35 | hasMany: true, 36 | }, 37 | { 38 | name: "content", 39 | type: "richText", 40 | }, 41 | { 42 | name: "status", 43 | type: "select", 44 | options: [ 45 | { 46 | value: "draft", 47 | label: "Draft", 48 | }, 49 | { 50 | value: "published", 51 | label: "Published", 52 | }, 53 | ], 54 | defaultValue: "draft", 55 | admin: { 56 | position: "sidebar", 57 | }, 58 | }, 59 | ], 60 | }; 61 | 62 | export default Posts; 63 | -------------------------------------------------------------------------------- /apps/server/src/collections/Tags.ts: -------------------------------------------------------------------------------- 1 | import type { CollectionConfig } from "payload/types"; 2 | 3 | const Tags: CollectionConfig = { 4 | slug: "tags", 5 | admin: { 6 | useAsTitle: "name", 7 | }, 8 | access: { 9 | read: () => true, 10 | }, 11 | fields: [ 12 | { 13 | name: "name", 14 | type: "text", 15 | }, 16 | ], 17 | timestamps: false, 18 | }; 19 | 20 | export default Tags; 21 | -------------------------------------------------------------------------------- /apps/server/src/collections/Users.ts: -------------------------------------------------------------------------------- 1 | import type { CollectionConfig } from "payload/types"; 2 | 3 | const Users: CollectionConfig = { 4 | slug: "users", 5 | auth: true, 6 | admin: { 7 | useAsTitle: "email", 8 | }, 9 | access: { 10 | read: () => true, 11 | }, 12 | fields: [ 13 | // Email added by default 14 | { 15 | name: "name", 16 | type: "text", 17 | }, 18 | ], 19 | }; 20 | 21 | export default Users; 22 | -------------------------------------------------------------------------------- /apps/server/src/payload-types.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /** 3 | * This file was automatically generated by Payload CMS. 4 | * DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config, 5 | * and re-run `payload generate:types` to regenerate this file. 6 | */ 7 | 8 | export interface Config { 9 | collections: { 10 | customers: Customer; 11 | categories: Category; 12 | posts: Post; 13 | tags: Tag; 14 | users: User; 15 | }; 16 | globals: {}; 17 | } 18 | export interface Customer { 19 | id: string; 20 | firstName: string; 21 | lastName: string; 22 | phoneNumber?: string; 23 | dateOfBirth?: string; 24 | gender?: ("male" | "female")[]; 25 | country?: string; 26 | state?: string; 27 | postalCode?: string; 28 | address?: string; 29 | nameOfNextKin?: string; 30 | phoneOfNextKin?: string; 31 | emailOfNextKin?: string; 32 | condition?: string; 33 | bloodPressure?: string; 34 | bloodSugar?: string; 35 | hba1cReading?: string; 36 | bodyMassIndex?: string; 37 | weight?: string; 38 | height?: string; 39 | viewPost?: string[] | Post[]; 40 | likes?: string[] | Post[]; 41 | likeCount?: number; 42 | email?: string; 43 | resetPasswordToken?: string; 44 | resetPasswordExpiration?: string; 45 | loginAttempts?: number; 46 | lockUntil?: string; 47 | createdAt: string; 48 | updatedAt: string; 49 | password?: string; 50 | } 51 | export interface Post { 52 | id: string; 53 | title?: string; 54 | author?: string | User; 55 | publishedDate?: string; 56 | category?: string | Category; 57 | tags?: string[] | Tag[]; 58 | content?: { 59 | [k: string]: unknown; 60 | }[]; 61 | status?: "draft" | "published"; 62 | createdAt: string; 63 | updatedAt: string; 64 | password?: string; 65 | } 66 | export interface User { 67 | id: string; 68 | name?: string; 69 | email?: string; 70 | resetPasswordToken?: string; 71 | resetPasswordExpiration?: string; 72 | loginAttempts?: number; 73 | lockUntil?: string; 74 | createdAt: string; 75 | updatedAt: string; 76 | password?: string; 77 | } 78 | export interface Category { 79 | id: string; 80 | name?: string; 81 | password?: string; 82 | } 83 | export interface Tag { 84 | id: string; 85 | name?: string; 86 | password?: string; 87 | } 88 | -------------------------------------------------------------------------------- /apps/server/src/payload.config.ts: -------------------------------------------------------------------------------- 1 | import Categories from "./collections/Categories"; 2 | import Posts from "./collections/Posts"; 3 | import Tags from "./collections/Tags"; 4 | import Users from "./collections/Users"; 5 | import Customers from "./collections/Customers"; 6 | import path from "path"; 7 | import { buildConfig } from "payload/config"; 8 | 9 | const clientUrls = [ 10 | "http://localhost:5173", 11 | process.env.PAYLOAD_PUBLIC_SERVER_URL, 12 | ]; 13 | 14 | export default buildConfig({ 15 | serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL, 16 | admin: { 17 | user: Users.slug, 18 | }, 19 | cors: clientUrls, 20 | csrf: clientUrls, 21 | collections: [Customers, Categories, Posts, Tags, Users], 22 | typescript: { 23 | outputFile: path.resolve(__dirname, "payload-types.ts"), 24 | }, 25 | graphQL: { 26 | schemaOutputFile: path.resolve(__dirname, "generated-schema.graphql"), 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /apps/server/src/server.mts: -------------------------------------------------------------------------------- 1 | import * as trpcExpress from "@trpc/server/adapters/express"; 2 | import cors from "cors"; 3 | import express from "express"; 4 | import payload from "payload"; 5 | import { appRouter } from "./trpc/router.mjs"; 6 | import { createContext } from "./trpc/context.mjs"; 7 | 8 | // NOTE: Just here as a placeholder for sveltekit 9 | // handler.mjs will be automatically converted to handler\.js (backslash to avoid conversion in comment) 10 | // and is the sveltekit entrypoint 11 | import { handler } from "./web/handler.mjs"; 12 | 13 | const app = express(); 14 | const port = process.env.PORT || 3000; 15 | 16 | // add multiple origins to allowlist 17 | app.use( 18 | cors({ 19 | origin: ["http://localhost:5173", process.env.PAYLOAD_PUBLIC_SERVER_URL], 20 | }) 21 | ); 22 | 23 | // Redirect root to Admin panel 24 | // app.get("/", (_, res) => { 25 | // res.redirect("/admin"); 26 | // }); 27 | 28 | // Add your own express routes here 29 | 30 | const start = async () => { 31 | // Initialize Payload 32 | await payload.init({ 33 | secret: process.env.PAYLOAD_SECRET, 34 | mongoURL: process.env.MONGO_URL, 35 | express: app, 36 | onInit: () => { 37 | payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`); 38 | }, 39 | }); 40 | 41 | app.use(payload.authenticate); 42 | 43 | app.use( 44 | "/trpc", 45 | trpcExpress.createExpressMiddleware({ 46 | router: appRouter, 47 | createContext, 48 | }) 49 | ); 50 | 51 | app.use(handler); 52 | 53 | app.listen(+port, () => { 54 | console.log(`API Server listening on port ${port}`); 55 | }); 56 | }; 57 | 58 | start(); 59 | -------------------------------------------------------------------------------- /apps/server/src/trpc/context.mts: -------------------------------------------------------------------------------- 1 | import type { CreateExpressContextOptions } from "@trpc/server/adapters/express"; 2 | import type { inferAsyncReturnType } from "@trpc/server"; 3 | import type { PayloadRequest } from "payload/types"; 4 | 5 | export const createContext = ({ 6 | req, 7 | res, 8 | }: CreateExpressContextOptions & { req: PayloadRequest }) => { 9 | return { req, res, user: req?.user }; 10 | }; 11 | 12 | export type Context = inferAsyncReturnType; 13 | -------------------------------------------------------------------------------- /apps/server/src/trpc/procedures.mts: -------------------------------------------------------------------------------- 1 | import superjson from "superjson"; 2 | import type { Context } from "./context.mjs"; 3 | import { initTRPC, TRPCError } from "@trpc/server"; 4 | 5 | const t = initTRPC.context().create({ 6 | transformer: superjson, 7 | errorFormatter({ shape }) { 8 | return shape; 9 | }, 10 | }); 11 | 12 | export const middleware = t.middleware; 13 | export const router = t.router; 14 | 15 | /** 16 | * Unprotected procedure 17 | */ 18 | export const publicProcedure = t.procedure; 19 | 20 | const isAuthed = middleware(({ next, ctx }) => { 21 | if (!ctx.user?.email) { 22 | throw new TRPCError({ 23 | code: "UNAUTHORIZED", 24 | }); 25 | } 26 | return next({ 27 | ctx: { 28 | // Infers the `session` as non-nullable 29 | user: ctx.user, 30 | }, 31 | }); 32 | }); 33 | 34 | /** 35 | * Protected procedure 36 | */ 37 | export const protectedProcedure = t.procedure.use(isAuthed); 38 | -------------------------------------------------------------------------------- /apps/server/src/trpc/router.mts: -------------------------------------------------------------------------------- 1 | import payload from "payload"; 2 | import user from "./routes/user.mjs"; 3 | import { publicProcedure } from "./procedures.mjs"; 4 | import { router } from "./procedures.mjs"; 5 | 6 | /* 7 | NOTE: 8 | Do not use path aliases for type imports else api consumers 9 | will get incorrect typings. 10 | */ 11 | 12 | export const appRouter = router({ 13 | greeting: publicProcedure.query(() => "Hello world!"), 14 | 15 | posts: publicProcedure.query(async () => { 16 | const posts = await payload.find({ 17 | collection: "posts", 18 | }); 19 | 20 | return posts; 21 | }), 22 | 23 | user, 24 | }); 25 | 26 | export type AppRouter = typeof appRouter; 27 | -------------------------------------------------------------------------------- /apps/server/src/trpc/routes/user.mts: -------------------------------------------------------------------------------- 1 | import { protectedProcedure, router } from "../procedures.mjs"; 2 | 3 | export default router({ 4 | self: protectedProcedure.query(({ ctx }) => { 5 | return ctx.user; 6 | }), 7 | }); 8 | -------------------------------------------------------------------------------- /apps/server/src/web/handler.mts: -------------------------------------------------------------------------------- 1 | /** 2 | * THIS IS A DUMMY FILE TO AVOID ERRORS IN THE server 3 | * BECAUSE THE WEB FOLDER IS BUILT BY THE FRONTEND 4 | */ 5 | 6 | import type { NextFunction } from "express"; 7 | 8 | export const handler = async (req, res, next: NextFunction) => { 9 | console.log("Request received"); 10 | next(); 11 | }; 12 | -------------------------------------------------------------------------------- /apps/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "strict": false, 7 | "esModuleInterop": true, 8 | "skipLibCheck": true, 9 | "outDir": "./dist", 10 | "rootDir": "./src", 11 | "jsx": "react", 12 | "importsNotUsedAsValues": "error", 13 | "moduleResolution": "node", 14 | "paths": { 15 | "payload/generated-types": ["./src/payload-types.ts"] 16 | } 17 | }, 18 | "include": ["src"], 19 | "exclude": ["node_modules", "dist", "build"], 20 | "ts-node": { 21 | "transpileOnly": true, 22 | "swc": true, 23 | "esm": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | .yarn/* 11 | !.yarn/releases 12 | !.yarn/plugins 13 | /misc -------------------------------------------------------------------------------- /apps/web/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /apps/web/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["antfu.unocss"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/web/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.tree.indent": 12 3 | } 4 | -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | | Technology | Usage | 6 | | ----------- | ----------------- | 7 | | [Sveltekit] | Svelte Framework | 8 | | [UnoCSS] | Atomic Css engine | 9 | 10 | ## Creating a project 11 | 12 | If you're seeing this, you've probably already done this step. Congrats! 13 | 14 | ```bash 15 | # create a new project in the current directory 16 | npx degit adroyt/sveltekit 17 | 18 | # create a new project in my-app 19 | npx degit adroyt/sveltekit my-app 20 | ``` 21 | 22 | ## Developing 23 | 24 | Once you've created a project and installed dependencies with `yarn` (or `npm install` or `pnpm install`), start a development server: 25 | 26 | ```bash 27 | yarn dev 28 | 29 | # or start the server and open the app in a new browser tab 30 | yarn dev -- --open 31 | ``` 32 | 33 | ## Building 34 | 35 | To create a production version of your app: 36 | 37 | ```bash 38 | yarn build 39 | ``` 40 | 41 | You can preview the production build with `yarn preview`. 42 | 43 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 44 | 45 | [sveltekit]: https://kit.svelte.dev 46 | [unocss]: https://github.com/unocss/unocss 47 | [vanilla extract]: https://vanilla-extract.style 48 | -------------------------------------------------------------------------------- /apps/web/my-preset.ts: -------------------------------------------------------------------------------- 1 | // my-preset.ts 2 | import type { Preset } from "unocss"; 3 | import { handler as h, variantGetParameter } from "@unocss/preset-mini/utils"; 4 | 5 | export const myPreset: Preset = { 6 | name: "my-preset", 7 | 8 | rules: [["abs", { position: "absolute" }]], 9 | 10 | shortcuts: [ 11 | [ 12 | // flex-s stands for flex-shortcut 13 | // to avoid mixups with default flex utilities like flex-wrap 14 | /^flex-s-(start|center|between|evenly|around|end)(-(start|center|baseline|end))?$/, 15 | ([, justify, align]) => 16 | `flex justify-${justify} items${align || "-center"}`, 17 | { layer: "default" }, 18 | ], 19 | // use when width and height values are the same 20 | [/^square-(.*)$/, ([, v]) => `h-${v} w-${v}`, { layer: "utilities" }], 21 | [ 22 | /^br(-\w+(-\w+)*)?$/, // h - hyphen | v - value 23 | ([, hAndV]) => { 24 | const [, v1, v2] = hAndV?.split("-") || []; 25 | // const vJoined = v.join("-"); 26 | return v2 27 | ? `rounded-${v1 + "-" + v2 || v2}` 28 | : v1 29 | ? `rounded-${v1}` 30 | : "rounded"; 31 | }, 32 | { layer: "default" }, 33 | ], 34 | [ 35 | /^scrollbar-f-(thin)-(.*)$/, 36 | ([, size, colors]) => 37 | `[scrollbar-width:${size}] [scrollbar-color:${colors}]`, 38 | { layer: "utilities" }, 39 | ], 40 | ], 41 | 42 | variants: [ 43 | { 44 | // adds support for "@min-[width]:class" and "@min-h-[width]:class" 45 | // or 46 | // "@min-width:class" and "@min-h-width:class" 47 | name: "arbitrary-media-query", 48 | match(matcher, { theme }) { 49 | // prefix with @ to specify that it's a media query 50 | const minVariant = variantGetParameter("@min-", matcher, [":", "-"]); 51 | const maxVariant = variantGetParameter("@max-", matcher, [":", "-"]); 52 | const minHeightVariant = variantGetParameter("@min-h-", matcher, [ 53 | ":", 54 | "-", 55 | ]); 56 | const maxHeightVariant = variantGetParameter("@max-h-", matcher, [ 57 | ":", 58 | "-", 59 | ]); 60 | 61 | // the order that we check the variants is important 62 | // because we want to match the most specific one 63 | const matched = 64 | (minHeightVariant && { 65 | type: "min-h", 66 | variant: minHeightVariant, 67 | }) || 68 | (maxHeightVariant && { 69 | type: "max-h", 70 | variant: maxHeightVariant, 71 | }) || 72 | (minVariant && { 73 | type: "min", 74 | variant: minVariant, 75 | }) || 76 | (maxVariant && { 77 | type: "max", 78 | variant: maxVariant, 79 | }); 80 | 81 | if (matched?.variant) { 82 | const [match, rest] = matched.variant; 83 | // this is for extracting the value from the match and 84 | // makes sure it either has no brackets or has brackets 85 | const extractedValue = 86 | h.bracket(match) || 87 | (!match.startsWith("[") && !match.endsWith("]") && match) || 88 | ""; 89 | const endsWithUnit = /^\d+(em|px|rem)$/.test(extractedValue); 90 | const isOnlyNum = /^\d+$/.test(extractedValue); 91 | 92 | if ( 93 | endsWithUnit || 94 | isOnlyNum || 95 | theme["breakpoints"][extractedValue] 96 | ) { 97 | return { 98 | matcher: rest, 99 | layer: "utilities", 100 | handle: (input, next) => 101 | next({ 102 | ...input, 103 | parent: `${ 104 | input.parent ? `${input.parent} $$ ` : "" 105 | }@media (${ 106 | matched.type == "min" 107 | ? "min-width" 108 | : matched.type == "max" 109 | ? "max-width" 110 | : matched.type == "min-h" 111 | ? "min-height" 112 | : "max-height" 113 | }:${ 114 | endsWithUnit 115 | ? extractedValue 116 | : isOnlyNum 117 | ? extractedValue + "px" 118 | : theme["breakpoints"][extractedValue] 119 | })`, 120 | }), 121 | }; 122 | } 123 | } 124 | }, 125 | }, 126 | { 127 | name: "firefox-only", 128 | match(matcher) { 129 | const ffVariant = variantGetParameter("@ff", matcher, [":"]); 130 | if (ffVariant) { 131 | const [, rest] = ffVariant; 132 | return { 133 | matcher: rest, 134 | handle: (input, next) => 135 | next({ 136 | ...input, 137 | parent: `${ 138 | input.parent ? `${input.parent} $$ ` : "" 139 | }@-moz-document url-prefix()`, 140 | }), 141 | }; 142 | } 143 | }, 144 | }, 145 | matcher => { 146 | const [m1, m2, m3] = [ 147 | "scrollbar:", 148 | "scrollbar-track:", 149 | "scrollbar-thumb:", 150 | ]; 151 | let matchedStr = ""; 152 | 153 | if (matcher.startsWith(m1)) { 154 | matchedStr = m1; 155 | } else if (matcher.startsWith(m2)) { 156 | matchedStr = m2; 157 | } else if (matcher.startsWith(m3)) { 158 | matchedStr = m3; 159 | } else { 160 | return matcher; 161 | } 162 | 163 | return { 164 | matcher: matcher.slice(matchedStr.length), 165 | selector: s => 166 | `${s}::-webkit-scrollbar${ 167 | matchedStr == m2 ? "-track" : matchedStr == m3 ? "-thumb" : "" 168 | }`, 169 | layer: "default", 170 | }; 171 | }, 172 | ], 173 | }; 174 | 175 | export function convertPalleteToHSL< 176 | T extends Record> 177 | >(obj: T) { 178 | const temp: Record> = {}; 179 | for (const colorKey in obj) { 180 | for (const colorShadeKey in obj[colorKey]) { 181 | if (!temp[colorKey]) { 182 | temp[colorKey] = { 183 | [colorShadeKey]: hexToHSL(obj[colorKey][colorShadeKey]), 184 | }; 185 | } else { 186 | temp[colorKey][colorShadeKey] = hexToHSL(obj[colorKey][colorShadeKey]); 187 | } 188 | } 189 | } 190 | return temp as T; 191 | } 192 | 193 | export function hexToHSL( 194 | hex: string, 195 | options?: { justNums: boolean; satAndLight?: { s?: number; l?: number } } 196 | ) { 197 | const { satAndLight, justNums } = options || { 198 | satAndLight: undefined, 199 | justNums: false, 200 | }; 201 | 202 | // convert hex to rgb 203 | let r = 0, 204 | g = 0, 205 | b = 0; 206 | if (hex.length === 4) { 207 | r = +("0x" + hex[1] + hex[1]); 208 | g = +("0x" + hex[2] + hex[2]); 209 | b = +("0x" + hex[3] + hex[3]); 210 | } else if (hex.length === 7) { 211 | r = +("0x" + hex[1] + hex[2]); 212 | g = +("0x" + hex[3] + hex[4]); 213 | b = +("0x" + hex[5] + hex[6]); 214 | } 215 | 216 | // then to HSL 217 | r /= 255; 218 | g /= 255; 219 | b /= 255; 220 | const cmin = Math.min(r, g, b); 221 | const cmax = Math.max(r, g, b); 222 | const delta = cmax - cmin; 223 | let h = 0; 224 | let s = 0; 225 | let l = 0; 226 | 227 | if (delta === 0) h = 0; 228 | else if (cmax === r) h = ((g - b) / delta) % 6; 229 | else if (cmax === g) h = (b - r) / delta + 2; 230 | else h = (r - g) / delta + 4; 231 | h = Math.round(h * 60); 232 | if (h < 0) h += 360; 233 | l = (cmax + cmin) / 2; 234 | s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); 235 | s = +(s * 100).toFixed(1); 236 | l = +(l * 100).toFixed(1); 237 | 238 | if (justNums) return `${h}, ${satAndLight?.s || s}%, ${satAndLight?.l || l}%`; 239 | 240 | return `hsl(${h}, ${satAndLight?.s || s}%, ${satAndLight?.l || l}%)`; 241 | } 242 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/web", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite dev", 8 | "build": "vite build", 9 | "build:win": "vite build", 10 | "preview": "vite preview", 11 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 12 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 13 | "lint": "prettier --check --ignore-path=../../.prettierignore . && eslint --ignore-path=../../.eslintignore .", 14 | "format": "prettier --write --ignore-path=../../.prettierignore ." 15 | }, 16 | "devDependencies": { 17 | "@apps/server": "workspace:*", 18 | "@iconify/json": "2.2.76", 19 | "@sveltejs/adapter-auto": "2.1.0", 20 | "@sveltejs/adapter-node": "^1.2.4", 21 | "@sveltejs/kit": "1.20.2", 22 | "@unocss/extractor-svelte": "^0.53.1", 23 | "@unocss/preset-mini": "^0.53.1", 24 | "@unocss/reset": "^0.53.1", 25 | "eslint-config-custom": "workspace:*", 26 | "svelte": "^3.59.1", 27 | "svelte-check": "^3.4.3", 28 | "tslib": "^2.5.3", 29 | "typescript": "^5.1.3", 30 | "unocss": "0.53.1", 31 | "vite": "^4.3.9" 32 | }, 33 | "dependencies": { 34 | "@trpc/client": "^10.29.1", 35 | "clsx": "^1.2.1", 36 | "superjson": "^1.12.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/web/src/additional-svelte-jsx.d.ts: -------------------------------------------------------------------------------- 1 | import type { AttributifyAttributes } from "@unocss/preset-attributify"; 2 | 3 | declare global { 4 | namespace svelte.JSX { 5 | interface HTMLAttributes extends AttributifyAttributes { 6 | [key: string]: unknown; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare namespace App { 5 | interface Locals { 6 | user: any; 7 | } 8 | // interface PageData {} 9 | // interface Error {} 10 | // interface Platform {} 11 | } 12 | -------------------------------------------------------------------------------- /apps/web/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /apps/web/src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | import { trpc } from "$lib/trpc"; 2 | import type { Handle } from "@sveltejs/kit"; 3 | 4 | export const handle: Handle = async ({ event, resolve }) => { 5 | const session = event.cookies.get("payload-token"); 6 | if (session) { 7 | const v = await trpc(event.fetch) 8 | .user.self.query() 9 | .catch(() => null); 10 | console.log(v); 11 | event.locals.user = v; 12 | } 13 | return await resolve(event); 14 | }; 15 | -------------------------------------------------------------------------------- /apps/web/src/lib/trpc/index.ts: -------------------------------------------------------------------------------- 1 | import superjson from "superjson"; 2 | import type { AppRouter } from "@apps/server"; 3 | import type { LoadEvent } from "@sveltejs/kit"; 4 | import { createTRPCProxyClient, httpBatchLink } from "@trpc/client"; 5 | import { env } from "$env/dynamic/public"; 6 | 7 | export const trpc = (loadFetch?: LoadEvent["fetch"]) => 8 | createTRPCProxyClient({ 9 | transformer: superjson, 10 | links: [ 11 | httpBatchLink({ 12 | url: env.PUBLIC_PAYLOAD_SERVER_URL + "/trpc", 13 | fetch(url, options) { 14 | if (loadFetch) { 15 | return loadFetch(url, { 16 | ...options, 17 | credentials: "include", 18 | }); 19 | } 20 | return fetch(url, { 21 | ...options, 22 | credentials: "include", 23 | }); 24 | }, 25 | }), 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /apps/web/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /apps/web/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sveltekit & Unocss template 6 | 7 | 8 | 42 | 43 |
44 | on-demand · instant · fully customizable 45 |
46 | -------------------------------------------------------------------------------- /apps/web/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanielu/sk-trpc-payload/366850259098d2b67ba118db757cc4b6edc761de/apps/web/static/favicon.png -------------------------------------------------------------------------------- /apps/web/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from "@sveltejs/adapter-node"; 2 | import { vitePreprocess } from "@sveltejs/kit/vite"; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | adapter: adapter({ 12 | out: "../server/dist/web", 13 | precompress: true, 14 | }), 15 | }, 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/uno.config.ts: -------------------------------------------------------------------------------- 1 | import extractorSvelte from "@unocss/extractor-svelte"; 2 | import { 3 | defineConfig, 4 | presetAttributify, 5 | presetIcons, 6 | presetUno, 7 | transformerDirectives, 8 | transformerVariantGroup, 9 | } from "unocss"; 10 | import { myPreset } from "./my-preset"; 11 | 12 | // https://unocss.dev 13 | export default defineConfig({ 14 | extractors: [extractorSvelte], 15 | theme: {}, 16 | rules: [], 17 | shortcuts: [], 18 | variants: [], 19 | 20 | preflights: [ 21 | { 22 | getCSS: () => ` 23 | :root { 24 | -webkit-tap-highlight-color: transparent; 25 | } 26 | 27 | html, 28 | body { 29 | overflow-x: hidden; 30 | height: 100%; 31 | } 32 | `, 33 | }, 34 | ], 35 | 36 | presets: [ 37 | myPreset, 38 | presetUno(), 39 | presetIcons({ scale: 1.2 }), 40 | presetAttributify(), 41 | ], 42 | transformers: [transformerDirectives(), transformerVariantGroup()], 43 | }); 44 | -------------------------------------------------------------------------------- /apps/web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from "@sveltejs/kit/vite"; 2 | import type { UserConfig } from "vite"; 3 | import unocss from "unocss/vite"; 4 | 5 | const config: UserConfig = { 6 | plugins: [unocss(), sveltekit()], 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build:no-logs": "dotenv -- turbo run build --output-logs=errors-only", 5 | "build": "dotenv -- turbo run build", 6 | "build:win": "dotenv -- turbo run build:win", 7 | "dev": "dotenv -- turbo run dev --parallel", 8 | "dev:web": "dotenv -- turbo run dev --filter=web", 9 | "dev:server": "dotenv -- turbo run dev --filter=server", 10 | "preview": "dotenv -- turbo run preview --parallel", 11 | "start:server": "dotenv -- turbo run start --filter=server", 12 | "start:server-win": "dotenv -- turbo run start:win --filter=server", 13 | "lint": "turbo run lint", 14 | "format": "prettier --write ." 15 | }, 16 | "devDependencies": { 17 | "@apps/web": "workspace:*", 18 | "dotenv-cli": "^7.2.1", 19 | "eslint": "^8.42.0", 20 | "eslint-config-custom": "workspace:*", 21 | "prettier": "^2.8.8", 22 | "prettier-plugin-svelte": "^2.10.1", 23 | "turbo": "^1.10.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/dum/README.md: -------------------------------------------------------------------------------- 1 | https://github.com/egoist/dum 2 | -------------------------------------------------------------------------------- /packages/dum/bin/dum.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanielu/sk-trpc-payload/366850259098d2b67ba118db757cc4b6edc761de/packages/dum/bin/dum.exe -------------------------------------------------------------------------------- /packages/dum/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/dum", 3 | "version": "0.0.0", 4 | "description": "A Rust scripts runner", 5 | "bin": "./bin/dum.exe" 6 | } 7 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | extends: [ 4 | "eslint:recommended", 5 | "plugin:@typescript-eslint/recommended", 6 | "turbo", 7 | "prettier", 8 | ], 9 | plugins: ["svelte3", "@typescript-eslint"], 10 | ignorePatterns: ["*.cjs"], 11 | overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }], 12 | settings: { 13 | "svelte3/typescript": () => require("typescript"), 14 | }, 15 | parserOptions: { 16 | sourceType: "module", 17 | ecmaVersion: 2020, 18 | }, 19 | env: { 20 | browser: true, 21 | es2017: true, 22 | node: true, 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-custom", 3 | "version": "0.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "@typescript-eslint/eslint-plugin": "^5.52.0", 8 | "@typescript-eslint/parser": "^5.52.0", 9 | "eslint-config-prettier": "^8.6.0", 10 | "eslint-config-turbo": "^0.0.7", 11 | "eslint-plugin-svelte3": "^4.0.0" 12 | }, 13 | "publishConfig": { 14 | "access": "public" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/replacer/README.md: -------------------------------------------------------------------------------- 1 | https://github.com/HanielU/replacer 2 | -------------------------------------------------------------------------------- /packages/replacer/bin/replacer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanielu/sk-trpc-payload/366850259098d2b67ba118db757cc4b6edc761de/packages/replacer/bin/replacer.exe -------------------------------------------------------------------------------- /packages/replacer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/replacer", 3 | "version": "0.0.0", 4 | "description": "A Rust CLI for replacing strings in files and directories", 5 | "bin": "./bin/replacer.exe" 6 | } 7 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /sveltekit-payload.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | }, 6 | { 7 | "path": "apps/web" 8 | }, 9 | { 10 | "path": "apps/server" 11 | }, 12 | { 13 | "path": "packages/eslint-config-custom" 14 | }, 15 | { 16 | "path": "packages/dum" 17 | }, 18 | { 19 | "path": "packages/replacer" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": [".svelte-kit/**", ".vercel/**"] 7 | }, 8 | "build:win": { 9 | "dependsOn": ["^build:win"], 10 | "outputs": [".svelte-kit/**"] 11 | }, 12 | "lint": { 13 | "outputs": [] 14 | }, 15 | "dev": { 16 | "cache": false 17 | }, 18 | "start": { 19 | "cache": false 20 | }, 21 | "start:win": { 22 | "cache": false 23 | }, 24 | "preview": { 25 | "cache": false 26 | }, 27 | 28 | "web#build": { 29 | "env": ["PUBLIC_PAYLOAD_SERVER_URL"] 30 | }, 31 | "server#build": { 32 | "env": [ 33 | "PUBLIC_PORT", 34 | "PORT", 35 | "PAYLOAD_SECRET", 36 | "MONGO_URL", 37 | "PAYLOAD_PUBLIC_SERVER_URL" 38 | ] 39 | }, 40 | 41 | "web#build:win": { 42 | "env": ["PUBLIC_PAYLOAD_SERVER_URL"] 43 | }, 44 | "server#build:win": { 45 | "env": [ 46 | "PORT", 47 | "PAYLOAD_SECRET", 48 | "MONGO_URL", 49 | "PAYLOAD_PUBLIC_SERVER_URL" 50 | ] 51 | } 52 | } 53 | } 54 | --------------------------------------------------------------------------------