├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .node-version ├── .prettierignore ├── .vscode ├── launch.json ├── qwik-city.code-snippets └── qwik.code-snippets ├── README.md ├── adapters └── cloudflare-pages │ └── vite.config.ts ├── package.json ├── pnpm-lock.yaml ├── public ├── _headers ├── _redirects ├── apple-touch-icon-180x180.png ├── favicon.ico ├── favicon.svg ├── fonts │ ├── poppins-400.woff2 │ ├── poppins-500.woff2 │ └── poppins-700.woff2 ├── manifest.json ├── maskable-icon-512x512.png ├── pwa-144x144.png ├── pwa-192x192.png ├── pwa-512x512.png ├── pwa-64x64.png ├── robots.txt └── screenshot.png ├── pwa-assets.config.ts ├── src ├── components │ ├── router-head │ │ └── router-head.tsx │ └── starter │ │ ├── counter │ │ ├── counter.module.css │ │ └── counter.tsx │ │ ├── footer │ │ ├── footer.module.css │ │ └── footer.tsx │ │ ├── gauge │ │ ├── gauge.module.css │ │ └── index.tsx │ │ ├── header │ │ ├── header.module.css │ │ └── header.tsx │ │ ├── hero │ │ ├── hero.module.css │ │ └── hero.tsx │ │ ├── icons │ │ └── qwik.tsx │ │ ├── infobox │ │ ├── infobox.module.css │ │ └── infobox.tsx │ │ └── next-steps │ │ ├── next-steps.module.css │ │ └── next-steps.tsx ├── entry.cloudflare-pages.tsx ├── entry.dev.tsx ├── entry.preview.tsx ├── entry.ssr.tsx ├── global.css ├── media │ └── thunder.png ├── root.tsx └── routes │ ├── demo │ ├── flower │ │ ├── flower.css │ │ └── index.tsx │ └── todolist │ │ ├── index.tsx │ │ └── todolist.module.css │ ├── index.tsx │ ├── layout.tsx │ ├── service-worker.ts │ └── styles.css ├── tsconfig.json └── vite.config.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.log 2 | **/.DS_Store 3 | *. 4 | .vscode/settings.json 5 | .history 6 | .yarn 7 | bazel-* 8 | bazel-bin 9 | bazel-out 10 | bazel-qwik 11 | bazel-testlogs 12 | dist 13 | dist-dev 14 | lib 15 | lib-types 16 | etc 17 | external 18 | node_modules 19 | temp 20 | tsc-out 21 | tsdoc-metadata.json 22 | target 23 | output 24 | rollup.config.js 25 | build 26 | .cache 27 | .vscode 28 | .rollup.cache 29 | dist 30 | tsconfig.tsbuildinfo 31 | vite.config.ts 32 | *.spec.tsx 33 | *.spec.ts 34 | .netlify 35 | pnpm-lock.yaml 36 | package-lock.json 37 | yarn.lock 38 | server 39 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | es2021: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/recommended", 11 | "plugin:qwik/recommended", 12 | ], 13 | parser: "@typescript-eslint/parser", 14 | parserOptions: { 15 | tsconfigRootDir: __dirname, 16 | project: ["./tsconfig.json"], 17 | ecmaVersion: 2021, 18 | sourceType: "module", 19 | ecmaFeatures: { 20 | jsx: true, 21 | }, 22 | }, 23 | plugins: ["@typescript-eslint"], 24 | rules: { 25 | "@typescript-eslint/no-explicit-any": "off", 26 | "@typescript-eslint/explicit-module-boundary-types": "off", 27 | "@typescript-eslint/no-inferrable-types": "off", 28 | "@typescript-eslint/no-non-null-assertion": "off", 29 | "@typescript-eslint/no-empty-interface": "off", 30 | "@typescript-eslint/no-namespace": "off", 31 | "@typescript-eslint/no-empty-function": "off", 32 | "@typescript-eslint/no-this-alias": "off", 33 | "@typescript-eslint/ban-types": "off", 34 | "@typescript-eslint/ban-ts-comment": "off", 35 | "prefer-spread": "off", 36 | "no-case-declarations": "off", 37 | "no-console": "off", 38 | "@typescript-eslint/no-unused-vars": ["error"], 39 | "@typescript-eslint/consistent-type-imports": "warn", 40 | "@typescript-eslint/no-unnecessary-condition": "warn", 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | /dist 3 | /lib 4 | /lib-types 5 | /server 6 | 7 | # Development 8 | node_modules 9 | *.local 10 | 11 | # Cache 12 | .cache 13 | .mf 14 | .rollup.cache 15 | tsconfig.tsbuildinfo 16 | 17 | # Logs 18 | logs 19 | *.log 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | pnpm-debug.log* 24 | lerna-debug.log* 25 | 26 | # Editor 27 | .vscode/* 28 | !.vscode/launch.json 29 | !.vscode/*.code-snippets 30 | 31 | .idea 32 | .DS_Store 33 | *.suo 34 | *.ntvs* 35 | *.njsproj 36 | *.sln 37 | *.sw? 38 | 39 | # Yarn 40 | .yarn/* 41 | !.yarn/releases 42 | 43 | # Cloudflare 44 | functions/**/*.js 45 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.log 2 | **/.DS_Store 3 | *. 4 | .vscode/settings.json 5 | .history 6 | .yarn 7 | bazel-* 8 | bazel-bin 9 | bazel-out 10 | bazel-qwik 11 | bazel-testlogs 12 | dist 13 | dist-dev 14 | lib 15 | lib-types 16 | etc 17 | external 18 | node_modules 19 | temp 20 | tsc-out 21 | tsdoc-metadata.json 22 | target 23 | output 24 | rollup.config.js 25 | build 26 | .cache 27 | .vscode 28 | .rollup.cache 29 | dist 30 | tsconfig.tsbuildinfo 31 | vite.config.ts 32 | *.spec.tsx 33 | *.spec.ts 34 | .netlify 35 | pnpm-lock.yaml 36 | package-lock.json 37 | yarn.lock 38 | server 39 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "name": "dev.debug", 10 | "request": "launch", 11 | "skipFiles": ["/**"], 12 | "cwd": "${workspaceFolder}", 13 | "program": "${workspaceFolder}/node_modules/vite/bin/vite.js", 14 | "args": ["--mode", "ssr", "--force"] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/qwik-city.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "onRequest": { 3 | "scope": "javascriptreact,typescriptreact", 4 | "prefix": "qonRequest", 5 | "description": "onRequest function for a route index", 6 | "body": [ 7 | "export const onRequest: RequestHandler = (request) => {", 8 | " $0", 9 | "};" 10 | ] 11 | }, 12 | "loader$": { 13 | "scope": "javascriptreact,typescriptreact", 14 | "prefix": "qloader$", 15 | "description": "loader$()", 16 | "body": ["export const $1 = routeLoader$(() => {", " $0", "});"] 17 | }, 18 | "action$": { 19 | "scope": "javascriptreact,typescriptreact", 20 | "prefix": "qaction$", 21 | "description": "action$()", 22 | "body": ["export const $1 = routeAction$((data) => {", " $0", "});"] 23 | }, 24 | "Full Page": { 25 | "scope": "javascriptreact,typescriptreact", 26 | "prefix": "qpage", 27 | "description": "Simple page component", 28 | "body": [ 29 | "import { component$ } from '@builder.io/qwik';", 30 | "", 31 | "export default component$(() => {", 32 | " $0", 33 | "});" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/qwik.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Qwik component (simple)": { 3 | "scope": "javascriptreact,typescriptreact", 4 | "prefix": "qcomponent$", 5 | "description": "Simple Qwik component", 6 | "body": [ 7 | "export const ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}} = component$(() => {", 8 | " return <${2:div}>$4", 9 | "});" 10 | ] 11 | }, 12 | "Qwik component (props)": { 13 | "scope": "typescriptreact", 14 | "prefix": "qcomponent$ + props", 15 | "description": "Qwik component w/ props", 16 | "body": [ 17 | "export interface ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}}Props {", 18 | " $2", 19 | "}", 20 | "", 21 | "export const $1 = component$<$1Props>((props) => {", 22 | " const ${2:count} = useSignal(0);", 23 | " return (", 24 | " <${3:div} on${4:Click}$={(ev) => {$5}}>", 25 | " $6", 26 | " ", 27 | " );", 28 | "});" 29 | ] 30 | }, 31 | "Qwik signal": { 32 | "scope": "javascriptreact,typescriptreact", 33 | "prefix": "quseSignal", 34 | "description": "useSignal() declaration", 35 | "body": ["const ${1:foo} = useSignal($2);", "$0"] 36 | }, 37 | "Qwik store": { 38 | "scope": "javascriptreact,typescriptreact", 39 | "prefix": "quseStore", 40 | "description": "useStore() declaration", 41 | "body": ["const ${1:state} = useStore({", " $2", "});", "$0"] 42 | }, 43 | "$ hook": { 44 | "scope": "javascriptreact,typescriptreact", 45 | "prefix": "q$", 46 | "description": "$() function hook", 47 | "body": ["$(() => {", " $0", "});", ""] 48 | }, 49 | "useVisibleTask": { 50 | "scope": "javascriptreact,typescriptreact", 51 | "prefix": "quseVisibleTask", 52 | "description": "useVisibleTask$() function hook", 53 | "body": ["useVisibleTask$(({ track }) => {", " $0", "});", ""] 54 | }, 55 | "useTask": { 56 | "scope": "javascriptreact,typescriptreact", 57 | "prefix": "quseTask$", 58 | "description": "useTask$() function hook", 59 | "body": [ 60 | "useTask$(({ track }) => {", 61 | " track(() => $1);", 62 | " $0", 63 | "});", 64 | "" 65 | ] 66 | }, 67 | "useResource": { 68 | "scope": "javascriptreact,typescriptreact", 69 | "prefix": "quseResource$", 70 | "description": "useResource$() declaration", 71 | "body": [ 72 | "const $1 = useResource$(({ track, cleanup }) => {", 73 | " $0", 74 | "});", 75 | "" 76 | ] 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qwik City App ⚡️ 2 | 3 | - [Qwik Docs](https://qwik.builder.io/) 4 | - [Discord](https://qwik.builder.io/chat) 5 | - [Qwik GitHub](https://github.com/BuilderIO/qwik) 6 | - [@QwikDev](https://twitter.com/QwikDev) 7 | - [Vite](https://vitejs.dev/) 8 | 9 | --- 10 | 11 | ## Project Structure 12 | 13 | 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. 14 | 15 | Inside your project, you'll see the following directory structure: 16 | 17 | ``` 18 | ├── public/ 19 | │ └── ... 20 | └── src/ 21 | ├── components/ 22 | │ └── ... 23 | └── routes/ 24 | └── ... 25 | ``` 26 | 27 | - `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. 28 | 29 | - `src/components`: Recommended directory for components. 30 | 31 | - `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. 32 | 33 | ## Add Integrations and deployment 34 | 35 | Use the `pnpm 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/). 36 | 37 | ```shell 38 | pnpm qwik add # or `pnpm qwik add` 39 | ``` 40 | 41 | ## Development 42 | 43 | Development mode uses [Vite's development server](https://vitejs.dev/). The `dev` command will server-side render (SSR) the output during development. 44 | 45 | ```shell 46 | npm start # or `pnpm start` 47 | ``` 48 | 49 | > Note: during dev mode, Vite may request a significant number of `.js` files. This does not represent a Qwik production build. 50 | 51 | ## Preview 52 | 53 | 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. 54 | 55 | ```shell 56 | pnpm preview # or `pnpm preview` 57 | ``` 58 | 59 | ## Production 60 | 61 | 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. 62 | 63 | ```shell 64 | pnpm build # or `pnpm build` 65 | ``` 66 | 67 | ## Static Site Generator (Node.js) 68 | 69 | ```shell 70 | pnpm build.server 71 | ``` 72 | 73 | ## Static Site Generator (Node.js) 74 | 75 | ```shell 76 | npm run build.server 77 | ``` 78 | 79 | ## Cloudflare Pages 80 | 81 | Cloudflare's [wrangler](https://github.com/cloudflare/wrangler) CLI can be used to preview a production build locally. To start a local server, run: 82 | 83 | ``` 84 | npm run serve 85 | ``` 86 | 87 | Then visit [http://localhost:8787/](http://localhost:8787/) 88 | 89 | ### Deployments 90 | 91 | [Cloudflare Pages](https://pages.cloudflare.com/) are deployable through their [Git provider integrations](https://developers.cloudflare.com/pages/platform/git-integration/). 92 | 93 | If you don't already have an account, then [create a Cloudflare account here](https://dash.cloudflare.com/sign-up/pages). Next go to your dashboard and follow the [Cloudflare Pages deployment guide](https://developers.cloudflare.com/pages/framework-guides/deploy-anything/). 94 | 95 | Within the projects "Settings" for "Build and deployments", the "Build command" should be `npm run build`, and the "Build output directory" should be set to `dist`. 96 | 97 | ### Function Invocation Routes 98 | 99 | Cloudflare Page's [function-invocation-routes config](https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes) can be used to include, or exclude, certain paths to be used by the worker functions. Having a `_routes.json` file gives developers more granular control over when your Function is invoked. 100 | This is useful to determine if a page response should be Server-Side Rendered (SSR) or if the response should use a static-site generated (SSG) `index.html` file. 101 | 102 | By default, the Cloudflare pages adaptor _does not_ include a `public/_routes.json` config, but rather it is auto-generated from the build by the Cloudflare adaptor. An example of an auto-generate `dist/_routes.json` would be: 103 | 104 | ``` 105 | { 106 | "include": [ 107 | "/*" 108 | ], 109 | "exclude": [ 110 | "/_headers", 111 | "/_redirects", 112 | "/build/*", 113 | "/favicon.ico", 114 | "/manifest.json", 115 | "/service-worker.js", 116 | "/about" 117 | ], 118 | "version": 1 119 | } 120 | ``` 121 | 122 | In the above example, it's saying _all_ pages should be SSR'd. However, the root static files such as `/favicon.ico` and any static assets in `/build/*` should be excluded from the Functions, and instead treated as a static file. 123 | 124 | In most cases the generated `dist/_routes.json` file is ideal. However, if you need more granular control over each path, you can instead provide you're own `public/_routes.json` file. When the project provides its own `public/_routes.json` file, then the Cloudflare adaptor will not auto-generate the routes config and instead use the committed one within the `public` directory. 125 | -------------------------------------------------------------------------------- /adapters/cloudflare-pages/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { cloudflarePagesAdapter } from "@builder.io/qwik-city/adapters/cloudflare-pages/vite"; 2 | import { extendConfig } from "@builder.io/qwik-city/vite"; 3 | import baseConfig from "../../vite.config"; 4 | 5 | export default extendConfig(baseConfig, () => { 6 | return { 7 | build: { 8 | ssr: true, 9 | rollupOptions: { 10 | input: ["src/entry.cloudflare-pages.tsx", "@qwik-city-plan"], 11 | }, 12 | }, 13 | plugins: [cloudflarePagesAdapter()], 14 | }; 15 | }); 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-qwik-basic-starter", 3 | "description": "Demo App with Routing built-in (recommended)", 4 | "engines": { 5 | "node": ">=15.0.0" 6 | }, 7 | "private": true, 8 | "trustedDependencies": [ 9 | "sharp" 10 | ], 11 | "scripts": { 12 | "build": "qwik build", 13 | "build.client": "vite build", 14 | "build.preview": "vite build --ssr src/entry.preview.tsx", 15 | "build.server": "vite build -c adapters/cloudflare-pages/vite.config.ts", 16 | "deploy": "wrangler pages publish ./dist", 17 | "dev": "vite --mode ssr", 18 | "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", 19 | "fmt": "prettier --write .", 20 | "fmt.check": "prettier --check .", 21 | "preview": "qwik build preview && vite preview", 22 | "serve": "wrangler pages dev ./dist", 23 | "start": "vite --open --mode ssr", 24 | "qwik": "qwik" 25 | }, 26 | "devDependencies": { 27 | "@builder.io/qwik": "^1.2.17", 28 | "@builder.io/qwik-city": "^1.2.17", 29 | "@types/eslint": "^8.44.4", 30 | "@types/node": "^20.8.4", 31 | "@typescript-eslint/eslint-plugin": "^6.7.5", 32 | "@typescript-eslint/parser": "^6.7.5", 33 | "@vite-pwa/assets-generator": "^0.0.10", 34 | "eslint": "^8.51.0", 35 | "eslint-plugin-qwik": "^1.2.17", 36 | "fast-glob": "^3.3.2", 37 | "prettier": "^3.0.3", 38 | "typescript": "^5.2.2", 39 | "undici": "^5.26.0", 40 | "vite": "^4.4.11", 41 | "vite-tsconfig-paths": "^4.2.1", 42 | "workbox-precaching": "^7.0.0", 43 | "workbox-routing": "^7.0.0", 44 | "workbox-strategies": "^7.0.0", 45 | "wrangler": "^3.0.0" 46 | }, 47 | "dependencies": { 48 | "vite-plugin-pwa": "^0.16.7" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /public/_headers: -------------------------------------------------------------------------------- 1 | # https://developers.cloudflare.com/pages/platform/headers/ 2 | 3 | /build/* 4 | Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable 5 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | # https://developers.cloudflare.com/pages/platform/redirects/ 2 | -------------------------------------------------------------------------------- /public/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/fonts/poppins-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/fonts/poppins-400.woff2 -------------------------------------------------------------------------------- /public/fonts/poppins-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/fonts/poppins-500.woff2 -------------------------------------------------------------------------------- /public/fonts/poppins-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/fonts/poppins-700.woff2 -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/web-manifest-combined.json", 3 | "name": "qwik-project-name", 4 | "short_name": "Welcome to Qwik", 5 | "start_url": ".", 6 | "display": "standalone", 7 | "background_color": "#fff", 8 | "description": "A Qwik project app.", 9 | "icons": [ 10 | { 11 | "src": "pwa-144x144.png", 12 | "sizes": "144x144", 13 | "type": "image/png" 14 | } 15 | ], 16 | "orientation": "portrait", 17 | "screenshots": [ 18 | { 19 | "src": "/screenshot.png", 20 | "type": "image/png", 21 | "sizes": "862x568" 22 | }, 23 | { 24 | "src": "/screenshot.png", 25 | "type": "image/png", 26 | "sizes": "862x568", 27 | "form_factor": "wide" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /public/maskable-icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/maskable-icon-512x512.png -------------------------------------------------------------------------------- /public/pwa-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/pwa-144x144.png -------------------------------------------------------------------------------- /public/pwa-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/pwa-192x192.png -------------------------------------------------------------------------------- /public/pwa-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/pwa-512x512.png -------------------------------------------------------------------------------- /public/pwa-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/pwa-64x64.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/robots.txt -------------------------------------------------------------------------------- /public/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aslemammad/qwik-pwa-example/76d215df11b707367487990adb5ba53f3f13f6d7/public/screenshot.png -------------------------------------------------------------------------------- /pwa-assets.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | } from '@vite-pwa/assets-generator/config' 4 | import type { Preset } from '@vite-pwa/assets-generator/config'; 5 | 6 | export const minimalPreset: Preset = { 7 | transparent: { 8 | sizes: [64, 144, 192, 512], 9 | favicons: [[64, 'favicon.ico']] 10 | }, 11 | maskable: { 12 | sizes: [512] 13 | }, 14 | apple: { 15 | sizes: [180] 16 | } 17 | } 18 | 19 | export default defineConfig({ 20 | preset: minimalPreset, 21 | images: ['public/favicon.svg'] 22 | }) -------------------------------------------------------------------------------- /src/components/router-head/router-head.tsx: -------------------------------------------------------------------------------- 1 | import { useDocumentHead, useLocation } from "@builder.io/qwik-city"; 2 | 3 | import { component$ } from "@builder.io/qwik"; 4 | 5 | /** 6 | * The RouterHead component is placed inside of the document `` element. 7 | */ 8 | export const RouterHead = component$(() => { 9 | const head = useDocumentHead(); 10 | const loc = useLocation(); 11 | 12 | return ( 13 | <> 14 | {head.title} 15 | 16 | 17 | 18 | 19 | 20 | {head.meta.map((m) => ( 21 | 22 | ))} 23 | 24 | {head.links.map((l) => ( 25 | 26 | ))} 27 | 28 | {head.styles.map((s) => ( 29 |