diff --git a/web/.eslintignore b/web/.eslintignore new file mode 100644 index 0000000..1acecc1 --- /dev/null +++ b/web/.eslintignore @@ -0,0 +1,38 @@ +**/*.log +**/.DS_Store +*. +.vscode/settings.json +.history +.yarn +bazel-* +bazel-bin +bazel-out +bazel-qwik +bazel-testlogs +dist +dist-dev +lib +lib-types +etc +external +node_modules +temp +tsc-out +tsdoc-metadata.json +target +output +rollup.config.js +build +.cache +.vscode +.rollup.cache +dist +tsconfig.tsbuildinfo +vite.config.ts +*.spec.tsx +*.spec.ts +.netlify +pnpm-lock.yaml +package-lock.json +yarn.lock +server diff --git a/web/.eslintrc.cjs b/web/.eslintrc.cjs new file mode 100644 index 0000000..70dc5d0 --- /dev/null +++ b/web/.eslintrc.cjs @@ -0,0 +1,42 @@ +module.exports = { + root: true, + env: { + browser: true, + es2021: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:qwik/recommended", + ], + parser: "@typescript-eslint/parser", + parserOptions: { + tsconfigRootDir: __dirname, + project: ["./tsconfig.json"], + ecmaVersion: 2021, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, + }, + plugins: ["@typescript-eslint"], + rules: { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-this-alias": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/ban-ts-comment": "off", + "prefer-spread": "off", + "no-case-declarations": "off", + "no-console": "off", + "@typescript-eslint/no-unused-vars": ["error"], + "@typescript-eslint/consistent-type-imports": "warn", + "@typescript-eslint/no-unnecessary-condition": "warn", + }, +}; diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..48dce73 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,41 @@ +# Build +/dist +/lib +/lib-types +/server + +# Development +node_modules +*.local + +# Cache +.cache +.mf +.rollup.cache +tsconfig.tsbuildinfo + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Editor +.vscode/* +!.vscode/launch.json +!.vscode/*.code-snippets + +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Yarn +.yarn/* +!.yarn/releases diff --git a/web/.prettierignore b/web/.prettierignore new file mode 100644 index 0000000..b62a968 --- /dev/null +++ b/web/.prettierignore @@ -0,0 +1,37 @@ +**/*.log +**/.DS_Store +*. +.vscode/settings.json +.history +.yarn +bazel-* +bazel-bin +bazel-out +bazel-qwik +bazel-testlogs +dist +dist-dev +lib +lib-types +etc +external +node_modules +temp +tsc-out +tsdoc-metadata.json +target +output +rollup.config.js +build +.cache +.vscode +.rollup.cache +tsconfig.tsbuildinfo +vite.config.ts +*.spec.tsx +*.spec.ts +.netlify +pnpm-lock.yaml +package-lock.json +yarn.lock +server diff --git a/web/.vscode/launch.json b/web/.vscode/launch.json new file mode 100644 index 0000000..e684cc8 --- /dev/null +++ b/web/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Chrome", + "request": "launch", + "type": "chrome", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}" + }, + { + "type": "node", + "name": "dev.debug", + "request": "launch", + "skipFiles": ["/**"], + "cwd": "${workspaceFolder}", + "program": "${workspaceFolder}/node_modules/vite/bin/vite.js", + "args": ["--mode", "ssr", "--force"] + } + ] +} diff --git a/web/.vscode/qwik-city.code-snippets b/web/.vscode/qwik-city.code-snippets new file mode 100644 index 0000000..878fcf6 --- /dev/null +++ b/web/.vscode/qwik-city.code-snippets @@ -0,0 +1,36 @@ +{ + "onRequest": { + "scope": "javascriptreact,typescriptreact", + "prefix": "qonRequest", + "description": "onRequest function for a route index", + "body": [ + "export const onRequest: RequestHandler = (request) => {", + " $0", + "};", + ], + }, + "loader$": { + "scope": "javascriptreact,typescriptreact", + "prefix": "qloader$", + "description": "loader$()", + "body": ["export const $1 = routeLoader$(() => {", " $0", "});"], + }, + "action$": { + "scope": "javascriptreact,typescriptreact", + "prefix": "qaction$", + "description": "action$()", + "body": ["export const $1 = routeAction$((data) => {", " $0", "});"], + }, + "Full Page": { + "scope": "javascriptreact,typescriptreact", + "prefix": "qpage", + "description": "Simple page component", + "body": [ + "import { component$ } from '@builder.io/qwik';", + "", + "export default component$(() => {", + " $0", + "});", + ], + }, +} diff --git a/web/.vscode/qwik.code-snippets b/web/.vscode/qwik.code-snippets new file mode 100644 index 0000000..62edc82 --- /dev/null +++ b/web/.vscode/qwik.code-snippets @@ -0,0 +1,78 @@ +{ + "Qwik component (simple)": { + "scope": "javascriptreact,typescriptreact", + "prefix": "qcomponent$", + "description": "Simple Qwik component", + "body": [ + "export const ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}} = component$(() => {", + " return <${2:div}>$4", + "});", + ], + }, + "Qwik component (props)": { + "scope": "typescriptreact", + "prefix": "qcomponent$ + props", + "description": "Qwik component w/ props", + "body": [ + "export interface ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}}Props {", + " $2", + "}", + "", + "export const $1 = component$<$1Props>((props) => {", + " const ${2:count} = useSignal(0);", + " return (", + " <${3:div} on${4:Click}$={(ev) => {$5}}>", + " $6", + " ", + " );", + "});", + ], + }, + "Qwik signal": { + "scope": "javascriptreact,typescriptreact", + "prefix": "quseSignal", + "description": "useSignal() declaration", + "body": ["const ${1:foo} = useSignal($2);", "$0"], + }, + "Qwik store": { + "scope": "javascriptreact,typescriptreact", + "prefix": "quseStore", + "description": "useStore() declaration", + "body": ["const ${1:state} = useStore({", " $2", "});", "$0"], + }, + "$ hook": { + "scope": "javascriptreact,typescriptreact", + "prefix": "q$", + "description": "$() function hook", + "body": ["$(() => {", " $0", "});", ""], + }, + "useVisibleTask": { + "scope": "javascriptreact,typescriptreact", + "prefix": "quseVisibleTask", + "description": "useVisibleTask$() function hook", + "body": ["useVisibleTask$(({ track }) => {", " $0", "});", ""], + }, + "useTask": { + "scope": "javascriptreact,typescriptreact", + "prefix": "quseTask$", + "description": "useTask$() function hook", + "body": [ + "useTask$(({ track }) => {", + " track(() => $1);", + " $0", + "});", + "", + ], + }, + "useResource": { + "scope": "javascriptreact,typescriptreact", + "prefix": "quseResource$", + "description": "useResource$() declaration", + "body": [ + "const $1 = useResource$(({ track, cleanup }) => {", + " $0", + "});", + "", + ], + }, +} diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..7f8f3c7 --- /dev/null +++ b/web/README.md @@ -0,0 +1,65 @@ +# Qwik City App ⚡️ + +- [Qwik Docs](https://qwik.builder.io/) +- [Discord](https://qwik.builder.io/chat) +- [Qwik GitHub](https://github.com/BuilderIO/qwik) +- [@QwikDev](https://twitter.com/QwikDev) +- [Vite](https://vitejs.dev/) + +--- + +## Project Structure + +This project is using Qwik with [QwikCity](https://qwik.builder.io/qwikcity/overview/). QwikCity is just an extra set of tools on top of Qwik to make it easier to build a full site, including directory-based routing, layouts, and more. + +Inside your project, you'll see the following directory structure: + +``` +├── public/ +│ └── ... +└── src/ + ├── components/ + │ └── ... + └── routes/ + └── ... +``` + +- `src/routes`: Provides the directory-based routing, which can include a hierarchy of `layout.tsx` layout files, and an `index.tsx` file as the page. Additionally, `index.ts` files are endpoints. Please see the [routing docs](https://qwik.builder.io/qwikcity/routing/overview/) for more info. + +- `src/components`: Recommended directory for components. + +- `public`: Any static assets, like images, can be placed in the public directory. Please see the [Vite public directory](https://vitejs.dev/guide/assets.html#the-public-directory) for more info. + +## Add Integrations and deployment + +Use the `yarn qwik add` command to add additional integrations. Some examples of integrations includes: Cloudflare, Netlify or Express Server, and the [Static Site Generator (SSG)](https://qwik.builder.io/qwikcity/guides/static-site-generation/). + +```shell +yarn qwik add # or `yarn qwik add` +``` + +## Development + +Development mode uses [Vite's development server](https://vitejs.dev/). The `dev` command will server-side render (SSR) the output during development. + +```shell +npm start # or `yarn start` +``` + +> Note: during dev mode, Vite may request a significant number of `.js` files. This does not represent a Qwik production build. + +## Preview + +The preview command will create a production build of the client modules, a production build of `src/entry.preview.tsx`, and run a local server. The preview server is only for convenience to preview a production build locally and should not be used as a production server. + +```shell +yarn preview # or `yarn preview` +``` + +## Production + +The production build will generate client and server modules by running both client and server build commands. The build command will use Typescript to run a type check on the source code. + +```shell +yarn build # or `yarn build` +``` diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..6a2227a --- /dev/null +++ b/web/package.json @@ -0,0 +1,42 @@ +{ + "name": "my-qwik-basic-starter", + "description": "Demo App with Routing built-in (recommended)", + "engines": { + "node": ">=15.0.0" + }, + "private": true, + "trustedDependencies": [ + "sharp" + ], + "type": "module", + "scripts": { + "build": "qwik build", + "build.client": "vite build", + "build.preview": "vite build --ssr src/entry.preview.tsx", + "build.types": "tsc --incremental --noEmit", + "deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'", + "dev": "vite --mode ssr", + "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", + "fmt": "prettier --write .", + "fmt.check": "prettier --check .", + "lint": "eslint \"src/**/*.ts*\"", + "preview": "qwik build preview && vite preview --open", + "start": "vite --open --mode ssr", + "qwik": "qwik" + }, + "devDependencies": { + "@builder.io/qwik": "^1.4.3", + "@builder.io/qwik-city": "^1.4.3", + "@types/eslint": "^8.56.2", + "@types/node": "^20.11.6", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "eslint": "^8.56.0", + "eslint-plugin-qwik": "^1.4.3", + "prettier": "^3.2.4", + "typescript": "5.3.3", + "undici": "*", + "vite": "^5.0.12", + "vite-tsconfig-paths": "^4.2.1" + } +} diff --git a/web/public/favicon.svg b/web/public/favicon.svg new file mode 100644 index 0000000..0ded7c1 --- /dev/null +++ b/web/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/fonts/poppins-400.woff2 b/web/public/fonts/poppins-400.woff2 new file mode 100644 index 0000000..b69e009 Binary files /dev/null and b/web/public/fonts/poppins-400.woff2 differ diff --git a/web/public/fonts/poppins-500.woff2 b/web/public/fonts/poppins-500.woff2 new file mode 100644 index 0000000..c660336 Binary files /dev/null and b/web/public/fonts/poppins-500.woff2 differ diff --git a/web/public/fonts/poppins-700.woff2 b/web/public/fonts/poppins-700.woff2 new file mode 100644 index 0000000..bf022fc Binary files /dev/null and b/web/public/fonts/poppins-700.woff2 differ diff --git a/web/public/manifest.json b/web/public/manifest.json new file mode 100644 index 0000000..c18e75f --- /dev/null +++ b/web/public/manifest.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/web-manifest-combined.json", + "name": "qwik-project-name", + "short_name": "Welcome to Qwik", + "start_url": ".", + "display": "standalone", + "background_color": "#fff", + "description": "A Qwik project app." +} diff --git a/web/public/robots.txt b/web/public/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/web/src/components/router-head/router-head.tsx b/web/src/components/router-head/router-head.tsx new file mode 100644 index 0000000..8d6134a --- /dev/null +++ b/web/src/components/router-head/router-head.tsx @@ -0,0 +1,37 @@ +import { useDocumentHead, useLocation } from "@builder.io/qwik-city"; + +import { component$ } from "@builder.io/qwik"; + +/** + * The RouterHead component is placed inside of the document `` element. + */ +export const RouterHead = component$(() => { + const head = useDocumentHead(); + const loc = useLocation(); + + return ( + <> + {head.title} + + + + + + {head.meta.map((m) => ( + + ))} + + {head.links.map((l) => ( + + ))} + + {head.styles.map((s) => ( +