Initialize web application via create-cloudflare CLI
Details: C3 = create-cloudflare@2.50.9 project name = dutylog framework = qwik framework cli = create-qwik@1.15.0 package manager = npm@10.8.2 wrangler = wrangler@4.29.0 git = 2.50.1
This commit is contained in:
commit
b1fb6794e8
|
@ -0,0 +1,52 @@
|
|||
# Build
|
||||
/dist
|
||||
/lib
|
||||
/lib-types
|
||||
/server
|
||||
|
||||
# Development
|
||||
node_modules
|
||||
.env
|
||||
*.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
|
||||
|
||||
# Cloudflare
|
||||
functions/**/*.js
|
||||
|
||||
# wrangler files
|
||||
.wrangler
|
||||
.dev.vars*
|
||||
!.dev.vars.example
|
||||
.env*
|
||||
!.env.example
|
|
@ -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
|
|
@ -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": ["<node_internals>/**"],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/node_modules/vite/bin/vite.js",
|
||||
"args": ["--mode", "ssr", "--force"]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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",
|
||||
"});",
|
||||
],
|
||||
},
|
||||
}
|
|
@ -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</$2>",
|
||||
"});",
|
||||
],
|
||||
},
|
||||
"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",
|
||||
" </${3}>",
|
||||
" );",
|
||||
"});",
|
||||
],
|
||||
},
|
||||
"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",
|
||||
"});",
|
||||
"",
|
||||
],
|
||||
},
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
# Qwik City App ⚡️
|
||||
|
||||
- [Qwik Docs](https://qwik.dev/)
|
||||
- [Discord](https://qwik.dev/chat)
|
||||
- [Qwik GitHub](https://github.com/QwikDev/qwik)
|
||||
- [@QwikDev](https://twitter.com/QwikDev)
|
||||
- [Vite](https://vitejs.dev/)
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
This project is using Qwik with [QwikCity](https://qwik.dev/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.dev/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 `npm run 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.dev/qwikcity/guides/static-site-generation/).
|
||||
|
||||
```shell
|
||||
npm run 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
|
||||
npm run 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
|
||||
npm run build # or `yarn build`
|
||||
```
|
||||
|
||||
## Cloudflare Pages
|
||||
|
||||
Cloudflare's [wrangler](https://github.com/cloudflare/wrangler) CLI can be used to preview a production build locally. To start a local server, run:
|
||||
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
Then visit [http://localhost:8787/](http://localhost:8787/)
|
||||
|
||||
### Deployments
|
||||
|
||||
[Cloudflare Pages](https://pages.cloudflare.com/) are deployable through their [Git provider integrations](https://developers.cloudflare.com/pages/platform/git-integration/).
|
||||
|
||||
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/).
|
||||
|
||||
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`.
|
||||
|
||||
### Function Invocation Routes
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
{
|
||||
"include": [
|
||||
"/*"
|
||||
],
|
||||
"exclude": [
|
||||
"/_headers",
|
||||
"/_redirects",
|
||||
"/build/*",
|
||||
"/favicon.ico",
|
||||
"/manifest.json",
|
||||
"/service-worker.js",
|
||||
"/about"
|
||||
],
|
||||
"version": 1
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
|
@ -0,0 +1,15 @@
|
|||
import { cloudflarePagesAdapter } from "@builder.io/qwik-city/adapters/cloudflare-pages/vite";
|
||||
import { extendConfig } from "@builder.io/qwik-city/vite";
|
||||
import baseConfig from "../../vite.config";
|
||||
|
||||
export default extendConfig(baseConfig, () => {
|
||||
return {
|
||||
build: {
|
||||
ssr: true,
|
||||
rollupOptions: {
|
||||
input: ["src/entry.cloudflare-pages.tsx", "@qwik-city-plan"],
|
||||
},
|
||||
},
|
||||
plugins: [cloudflarePagesAdapter()],
|
||||
};
|
||||
});
|
|
@ -0,0 +1,73 @@
|
|||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
import { globalIgnores } from "eslint/config";
|
||||
import { qwikEslint9Plugin } from "eslint-plugin-qwik";
|
||||
|
||||
const ignores = [
|
||||
"**/*.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",
|
||||
"eslint.config.js",
|
||||
];
|
||||
|
||||
export default tseslint.config(
|
||||
globalIgnores(ignores),
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
qwikEslint9Plugin.configs.recommended,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
...globals.es2021,
|
||||
...globals.serviceworker,
|
||||
},
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
},
|
||||
);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "my-qwik-basic-starter",
|
||||
"description": "Demo app with sample routes",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"engines-annotation": "Mostly required by sharp which needs a Node-API v9 compatible runtime",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "qwik build",
|
||||
"build.client": "vite build",
|
||||
"build.preview": "vite build --ssr src/entry.preview.tsx",
|
||||
"build.server": "vite build -c adapters/cloudflare-pages/vite.config.ts",
|
||||
"build.types": "tsc --incremental --noEmit",
|
||||
"deploy": "npm run build && wrangler deploy",
|
||||
"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": "npm run build && wrangler dev",
|
||||
"serve": "wrangler pages dev ./dist --compatibility-flags=nodejs_als",
|
||||
"start": "vite --open --mode ssr",
|
||||
"qwik": "qwik",
|
||||
"cf-typegen": "wrangler types"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@builder.io/qwik": "^1.15.0",
|
||||
"@builder.io/qwik-city": "^1.15.0",
|
||||
"@cloudflare/workers-types": "^4.20250816.0",
|
||||
"@eslint/js": "latest",
|
||||
"@types/node": "^20.14.11",
|
||||
"eslint": "9.25.1",
|
||||
"eslint-plugin-qwik": "^1.15.0",
|
||||
"globals": "16.0.0",
|
||||
"prettier": "3.3.3",
|
||||
"typescript": "5.4.5",
|
||||
"typescript-eslint": "8.26.1",
|
||||
"typescript-plugin-css-modules": "latest",
|
||||
"undici": "*",
|
||||
"vite": "5.3.5",
|
||||
"vite-tsconfig-paths": "^4.2.1",
|
||||
"wrangler": "^3.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
_worker.js
|
||||
_routes.json
|
||||
_headers
|
||||
_redirects
|
|
@ -0,0 +1,11 @@
|
|||
# https://developers.cloudflare.com/pages/platform/headers/
|
||||
|
||||
/*service-worker.js
|
||||
Cache-Control: no-store
|
||||
Content-Type: application/javascript
|
||||
X-Content-Type-Options: nosniff
|
||||
|
||||
/build/*
|
||||
Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable
|
||||
/assets/*
|
||||
Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable
|
|
@ -0,0 +1 @@
|
|||
# https://developers.cloudflare.com/pages/platform/redirects/
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 500 500"><g clip-path="url(#a)"><circle cx="250" cy="250" r="250" fill="#fff"/><path fill="#18B6F6" d="m367.87 418.45-61.17-61.18-.94.13v-.67L175.7 227.53l32.05-31.13L188.9 87.73 99.56 199.09c-15.22 15.42-18.03 40.51-7.08 59.03l55.83 93.11a46.82 46.82 0 0 0 40.73 22.81l27.65-.27 151.18 44.68Z"/><path fill="#AC7EF4" d="m401.25 196.94-12.29-22.81-6.41-11.67-2.54-4.56-.26.26-33.66-58.63a47.07 47.07 0 0 0-41.27-23.75l-29.51.8-88.01.28a47.07 47.07 0 0 0-40.33 23.34L93.4 207l95.76-119.54L314.7 226.19l-22.3 22.67 13.35 108.54.13-.26v.26h-.26l.26.27 10.42 10.2 50.62 49.78c2.13 2 5.6-.4 4.13-2.96l-31.25-61.85 54.5-101.3 1.73-2c.67-.81 1.33-1.62 1.87-2.42a46.8 46.8 0 0 0 3.34-50.18Z"/><path fill="#fff" d="M315.1 225.65 189.18 87.6l17.9 108.14L175 227l130.5 130.27-11.75-108.14 21.37-23.48Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h500v500H0z"/></clipPath></defs></svg>
|
After Width: | Height: | Size: 947 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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."
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// This file can be used to add references for global types like `vite/client`.
|
||||
|
||||
// Add global `vite/client` types. For more info, see: https://vitejs.dev/guide/features#client-types
|
||||
/// <reference types="vite/client" />
|
|
@ -0,0 +1,49 @@
|
|||
import { useDocumentHead, useLocation } from "@builder.io/qwik-city";
|
||||
|
||||
import { component$ } from "@builder.io/qwik";
|
||||
|
||||
/**
|
||||
* The RouterHead component is placed inside of the document `<head>` element.
|
||||
*/
|
||||
export const RouterHead = component$(() => {
|
||||
const head = useDocumentHead();
|
||||
const loc = useLocation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<title>{head.title}</title>
|
||||
|
||||
<link rel="canonical" href={loc.url.href} />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
|
||||
{head.meta.map((m) => (
|
||||
<meta key={m.key} {...m} />
|
||||
))}
|
||||
|
||||
{head.links.map((l) => (
|
||||
<link key={l.key} {...l} />
|
||||
))}
|
||||
|
||||
{head.styles.map((s) => (
|
||||
<style
|
||||
key={s.key}
|
||||
{...s.props}
|
||||
{...(s.props?.dangerouslySetInnerHTML
|
||||
? {}
|
||||
: { dangerouslySetInnerHTML: s.style })}
|
||||
/>
|
||||
))}
|
||||
|
||||
{head.scripts.map((s) => (
|
||||
<script
|
||||
key={s.key}
|
||||
{...s.props}
|
||||
{...(s.props?.dangerouslySetInnerHTML
|
||||
? {}
|
||||
: { dangerouslySetInnerHTML: s.script })}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
.counter-wrapper {
|
||||
margin-top: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.counter-wrapper {
|
||||
gap: 30px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { component$, useSignal, $ } from "@builder.io/qwik";
|
||||
import styles from "./counter.module.css";
|
||||
import Gauge from "../gauge";
|
||||
|
||||
export default component$(() => {
|
||||
const count = useSignal(70);
|
||||
|
||||
const setCount = $((newValue: number) => {
|
||||
if (newValue < 0 || newValue > 100) {
|
||||
return;
|
||||
}
|
||||
count.value = newValue;
|
||||
});
|
||||
|
||||
return (
|
||||
<div class={styles["counter-wrapper"]}>
|
||||
<button
|
||||
class="button-dark button-small"
|
||||
onClick$={() => setCount(count.value - 1)}
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<Gauge value={count.value} />
|
||||
<button
|
||||
class="button-dark button-small"
|
||||
onClick$={() => setCount(count.value + 1)}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
.anchor {
|
||||
color: white !important;
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.anchor span:not(.spacer) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
display: none;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.anchor span {
|
||||
display: inline !important;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import { useServerTimeLoader } from "../../../routes/layout";
|
||||
import styles from "./footer.module.css";
|
||||
|
||||
export default component$(() => {
|
||||
const serverTime = useServerTimeLoader();
|
||||
|
||||
return (
|
||||
<footer>
|
||||
<div class="container">
|
||||
<a href="https://www.builder.io/" target="_blank" class={styles.anchor}>
|
||||
<span>Made with ♡ by Builder.io</span>
|
||||
<span class={styles.spacer}>|</span>
|
||||
<span>{serverTime.value.date}</span>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
.wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gauge {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.value {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
color: white;
|
||||
font-size: 3rem;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.gauge {
|
||||
width: 400px;
|
||||
}
|
||||
.value {
|
||||
font-size: 7rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import styles from "./gauge.module.css";
|
||||
|
||||
export default component$(({ value = 50 }: { value?: number }) => {
|
||||
const safeValue = value < 0 || value > 100 ? 50 : value;
|
||||
|
||||
return (
|
||||
<div class={styles.wrapper}>
|
||||
<svg viewBox="0 0 120 120" class={styles.gauge}>
|
||||
<defs>
|
||||
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#18B6F6" />
|
||||
<stop offset="1000%" stop-color="#AC7FF4" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<circle
|
||||
r="56"
|
||||
cx="60"
|
||||
cy="60"
|
||||
stroke-width="8"
|
||||
style="fill: #000; stroke: #0000"
|
||||
></circle>
|
||||
|
||||
<circle
|
||||
r="56"
|
||||
cx="60"
|
||||
cy="60"
|
||||
stroke-width="8"
|
||||
style={`transform: rotate(-87.9537deg); stroke-dasharray: ${
|
||||
safeValue * 3.51
|
||||
}, 351.858; fill:none; transform-origin:50% 50%; stroke-linecap:round; stroke:url(#gradient)`}
|
||||
></circle>
|
||||
</svg>
|
||||
<span class={styles.value}>{safeValue}</span>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
.wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: inline-block;
|
||||
}
|
||||
.logo a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.header li {
|
||||
display: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.header li a {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.header li a:hover {
|
||||
color: var(--qwik-light-blue);
|
||||
}
|
||||
|
||||
@media (min-width: 450px) {
|
||||
.header li {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import { QwikLogo } from "../icons/qwik";
|
||||
import styles from "./header.module.css";
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<header class={styles.header}>
|
||||
<div class={["container", styles.wrapper]}>
|
||||
<div class={styles.logo}>
|
||||
<a href="/" title="qwik">
|
||||
<QwikLogo height={50} width={143} />
|
||||
</a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://qwik.dev/docs/components/overview/"
|
||||
target="_blank"
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://qwik.dev/examples/introduction/hello-world/"
|
||||
target="_blank"
|
||||
>
|
||||
Examples
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://qwik.dev/tutorial/welcome/overview/"
|
||||
target="_blank"
|
||||
>
|
||||
Tutorials
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
.hero {
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
height: 450px;
|
||||
justify-content: center;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.hero-image {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
z-index: -1;
|
||||
opacity: 0.2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
color: white;
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.hero {
|
||||
gap: 60px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import styles from "./hero.module.css";
|
||||
import ImgThunder from "../../../media/thunder.png?jsx";
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<div class={["container", styles.hero]}>
|
||||
<ImgThunder class={styles["hero-image"]} alt="Image thunder" />
|
||||
<h1>
|
||||
So <span class="highlight">fantastic</span>
|
||||
<br />
|
||||
to have <span class="highlight">you</span> here
|
||||
</h1>
|
||||
<p>Have fun building your App with Qwik.</p>
|
||||
<div class={styles["button-group"]}>
|
||||
<button
|
||||
onClick$={async () => {
|
||||
const defaults = {
|
||||
spread: 360,
|
||||
ticks: 70,
|
||||
gravity: 0,
|
||||
decay: 0.95,
|
||||
startVelocity: 30,
|
||||
colors: ["006ce9", "ac7ff4", "18b6f6", "713fc2", "ffffff"],
|
||||
origin: {
|
||||
x: 0.5,
|
||||
y: 0.35,
|
||||
},
|
||||
};
|
||||
|
||||
function loadConfetti() {
|
||||
return new Promise<(opts: any) => void>((resolve, reject) => {
|
||||
if ((globalThis as any).confetti) {
|
||||
return resolve((globalThis as any).confetti as any);
|
||||
}
|
||||
const script = document.createElement("script");
|
||||
script.src =
|
||||
"https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js";
|
||||
script.onload = () =>
|
||||
resolve((globalThis as any).confetti as any);
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
script.remove();
|
||||
});
|
||||
}
|
||||
|
||||
const confetti = await loadConfetti();
|
||||
|
||||
function shoot() {
|
||||
confetti({
|
||||
...defaults,
|
||||
particleCount: 80,
|
||||
scalar: 1.2,
|
||||
});
|
||||
|
||||
confetti({
|
||||
...defaults,
|
||||
particleCount: 60,
|
||||
scalar: 0.75,
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(shoot, 0);
|
||||
setTimeout(shoot, 100);
|
||||
setTimeout(shoot, 200);
|
||||
setTimeout(shoot, 300);
|
||||
setTimeout(shoot, 400);
|
||||
}}
|
||||
>
|
||||
Time to celebrate
|
||||
</button>
|
||||
<a
|
||||
href="https://qwik.dev/docs"
|
||||
target="_blank"
|
||||
class="button button-dark"
|
||||
>
|
||||
Explore the docs
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
export const QwikLogo = ({
|
||||
width = 100,
|
||||
height = 35,
|
||||
}: {
|
||||
width?: number;
|
||||
height?: number;
|
||||
}) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 167 53"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M81.9545 46.5859H75.5513V35.4045C73.4363 36.8579 71.0496 37.5749 68.4884 37.5749C65.0151 37.5749 62.4344 36.6253 60.8239 34.6487C59.2134 32.6915 58.3984 29.2034 58.3984 24.2231C58.3984 19.1266 59.3492 15.5997 61.2702 13.5456C63.23 11.4721 66.3734 10.4644 70.7004 10.4644C74.7946 10.4644 78.5201 11.0264 81.9545 12.131V46.5859ZM75.5513 16.278C74.096 15.8323 72.4661 15.6191 70.7004 15.6191C68.5272 15.6191 66.9749 16.1811 66.1017 17.3244C65.2479 18.4871 64.7823 20.6962 64.7823 23.9712C64.7823 27.0524 65.1897 29.1065 66.0435 30.2304C66.8973 31.335 68.3719 31.897 70.5452 31.897C73.3781 31.897 75.5513 30.7343 75.5513 29.2809V16.278Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M91.133 11.1426C93.4033 17.4406 95.3242 23.7386 96.993 30.0948C99.205 23.5836 101.087 17.2856 102.542 11.1426H108.15C110.265 17.4406 112.031 23.7386 113.447 30.0948C115.97 23.196 117.949 16.8787 119.404 11.1426H125.71C123.033 20.173 120.064 28.777 116.785 36.8966H109.256C108.402 32.3039 107.044 26.7617 105.22 20.1536C104.056 25.2889 102.445 30.8893 100.33 36.8966H92.8018C90.2793 27.5174 87.5434 18.9522 84.6328 11.1426H91.133Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M132.832 7.55758C129.999 7.55758 129.203 6.85996 129.203 3.97257C129.203 1.39523 130.018 0.794495 132.832 0.794495C135.665 0.794495 136.46 1.39523 136.46 3.97257C136.46 6.85996 135.665 7.55758 132.832 7.55758ZM129.649 11.1426H136.053V36.8966H129.649V11.1426Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M166.303 11.1426C161.763 17.5956 158.581 21.5295 156.815 22.9441C158.27 23.8937 162.17 28.8933 167.002 36.916H159.628C153.613 27.7887 150.742 23.8549 149.325 23.2542V36.916H142.922V0H149.325V23.2348C150.78 22.169 153.963 18.1382 158.872 11.1426H166.303Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M40.973 52.5351L32.0861 43.6985L31.9503 43.7179V43.621L13.0511 24.9595L17.708 20.4637L14.9721 4.76715L1.99103 20.8513C-0.220992 23.0798 -0.628467 26.7036 0.962635 29.3778L9.07337 42.8265C10.3152 44.9 12.566 46.1402 14.9915 46.1208L19.0081 46.082L40.973 52.5351Z"
|
||||
fill="#18B6F6"
|
||||
/>
|
||||
<path
|
||||
d="M45.8232 20.5411L44.038 17.2468L43.1066 15.5609L42.738 14.902L42.6992 14.9408L37.8094 6.47238C36.587 4.34075 34.2974 3.02301 31.8137 3.04239L27.5255 3.15865L14.7384 3.19741C12.313 3.21679 10.101 4.49577 8.87853 6.56927L1.09766 21.9945L15.0101 4.72831L33.2496 24.7656L30.0091 28.0406L31.9495 43.7178L31.9689 43.679V43.7178H31.9301L31.9689 43.7565L33.4824 45.2293L40.8364 52.4187C41.1469 52.7094 41.6514 52.3606 41.4379 51.9924L36.8975 43.0589L44.8142 28.4282L45.0664 28.1375C45.1634 28.0212 45.2604 27.905 45.3381 27.7887C46.8904 25.6764 47.1038 22.8472 45.8232 20.5411Z"
|
||||
fill="#AC7EF4"
|
||||
/>
|
||||
<path
|
||||
d="M33.3076 24.6882L15.0099 4.74774L17.61 20.3668L12.9531 24.882L31.9105 43.6985L30.203 28.0794L33.3076 24.6882Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
|
@ -0,0 +1,23 @@
|
|||
.infobox {
|
||||
color: white;
|
||||
font-size: 0.8rem;
|
||||
line-height: 2;
|
||||
margin: 0 0 40px;
|
||||
}
|
||||
|
||||
.infobox h3 {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
margin: 0 0 15px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.infobox li {
|
||||
line-height: 2.5;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
.infobox {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { Slot, component$ } from "@builder.io/qwik";
|
||||
import styles from "./infobox.module.css";
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<div class={styles.infobox}>
|
||||
<h3>
|
||||
<Slot name="title" />
|
||||
</h3>
|
||||
<Slot />
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
.gettingstarted {
|
||||
display: flex;
|
||||
color: white;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 280px;
|
||||
line-height: 1.5;
|
||||
gap: 10px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.gettingstarted .intro {
|
||||
font-size: 1rem;
|
||||
width: 100%;
|
||||
word-break: break-word;
|
||||
}
|
||||
.gettingstarted .hint {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.gettingstarted .hint a {
|
||||
color: var(--qwik-dark-purple);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.gettingstarted {
|
||||
height: 180px;
|
||||
}
|
||||
.gettingstarted .intro {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.gettingstarted .hint {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import { component$, $, useOnWindow, useSignal } from "@builder.io/qwik";
|
||||
import styles from "./next-steps.module.css";
|
||||
|
||||
export const GETTING_STARTED_STEPS = [
|
||||
{
|
||||
message:
|
||||
"Press and hold the <b>ALT/Option</b> key to activate 'Click-to-Source' mode",
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Select the title of this page while keeping the <b>ALT/Option</b> key pressed",
|
||||
hint: 'Edit the title and save the changes. If your editor does not open, have a look at <a href="https://github.com/yyx990803/launch-editor#supported-editors" target="_blank">this page</a> to set the correct <code>LAUNCH_EDITOR</code> value.',
|
||||
},
|
||||
{
|
||||
message:
|
||||
"<b>Update</b> now the <code>routeLoader$</code> defined in the <code>src/routes/layout.tsx</code> file",
|
||||
hint: "Instead of returning the current date, you could return any possible string.<br />The output is displayed in the footer.",
|
||||
},
|
||||
{
|
||||
message: "Create a <b>new Route</b> called <code>/me</code>",
|
||||
hint: 'Create a new directory called <code>me</code> in <code>src/routes</code>. Within this directory create a <code>index.tsx</code> file or copy the <code>src/routes/index.tsx</code> file. Your new route is now accessible <a href="/me" target="_blank">here</a> ✨',
|
||||
},
|
||||
{
|
||||
message: "Time to have a look at <b>Forms</b>",
|
||||
hint: 'Open <a href="/demo/todolist" target="_blank">the TODO list App</a> and add some items to the list. Try the same with disabled JavaScript 🐰',
|
||||
},
|
||||
{
|
||||
message: "<b>Congratulations!</b> You are now familiar with the basics! 🎉",
|
||||
hint: "If you need further info on how to use qwik, have a look at <a href='https://qwik.dev' target='_blank'>qwik.dev</a> or join the <a href='https://qwik.dev/chat' target='_blank'>Discord channel</a>.",
|
||||
},
|
||||
];
|
||||
|
||||
export default component$(() => {
|
||||
const gettingStartedStep = useSignal(0);
|
||||
|
||||
useOnWindow(
|
||||
"keydown",
|
||||
$((e) => {
|
||||
if ((e as KeyboardEvent).key === "Alt") {
|
||||
gettingStartedStep.value = 1;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
<div class="container container-purple container-center">
|
||||
<h2>
|
||||
Time for a
|
||||
<br />
|
||||
<span class="highlight">qwik intro</span>?
|
||||
</h2>
|
||||
<div class={styles.gettingstarted}>
|
||||
<div
|
||||
class={styles.intro}
|
||||
dangerouslySetInnerHTML={
|
||||
GETTING_STARTED_STEPS[gettingStartedStep.value].message
|
||||
}
|
||||
/>
|
||||
<span
|
||||
class={styles.hint}
|
||||
dangerouslySetInnerHTML={
|
||||
GETTING_STARTED_STEPS[gettingStartedStep.value].hint
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{gettingStartedStep.value + 1 < GETTING_STARTED_STEPS.length ? (
|
||||
<button class="button-dark" onClick$={() => gettingStartedStep.value++}>
|
||||
Continue with Step {gettingStartedStep.value + 2} of{" "}
|
||||
{GETTING_STARTED_STEPS.length}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
class="button-dark"
|
||||
onClick$={() => (gettingStartedStep.value = 0)}
|
||||
>
|
||||
Re-Start
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* It's the entry point for Cloudflare Pages when building for production.
|
||||
*
|
||||
* Learn more about the Cloudflare Pages integration here:
|
||||
* - https://qwik.dev/docs/deployments/cloudflare-pages/
|
||||
*
|
||||
*/
|
||||
import {
|
||||
createQwikCity,
|
||||
type PlatformCloudflarePages,
|
||||
} from "@builder.io/qwik-city/middleware/cloudflare-pages";
|
||||
import qwikCityPlan from "@qwik-city-plan";
|
||||
import render from "./entry.ssr";
|
||||
|
||||
declare global {
|
||||
interface QwikCityPlatform extends PlatformCloudflarePages {
|
||||
env: Env
|
||||
}
|
||||
}
|
||||
|
||||
const fetch = createQwikCity({ render, qwikCityPlan });
|
||||
|
||||
export { fetch };
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* Development entry point using only client-side modules:
|
||||
* - Do not use this mode in production!
|
||||
* - No SSR
|
||||
* - No portion of the application is pre-rendered on the server.
|
||||
* - All of the application is running eagerly in the browser.
|
||||
* - More code is transferred to the browser than in SSR mode.
|
||||
* - Optimizer/Serialization/Deserialization code is not exercised!
|
||||
*/
|
||||
import { render, type RenderOptions } from "@builder.io/qwik";
|
||||
import Root from "./root";
|
||||
|
||||
export default function (opts: RenderOptions) {
|
||||
return render(document, <Root />, opts);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* It's the bundle entry point for `npm run preview`.
|
||||
* That is, serving your app built in production mode.
|
||||
*
|
||||
* Feel free to modify this file, but don't remove it!
|
||||
*
|
||||
* Learn more about Vite's preview command:
|
||||
* - https://vitejs.dev/config/preview-options.html#preview-options
|
||||
*
|
||||
*/
|
||||
import { createQwikCity } from "@builder.io/qwik-city/middleware/node";
|
||||
import qwikCityPlan from "@qwik-city-plan";
|
||||
// make sure qwikCityPlan is imported before entry
|
||||
import render from "./entry.ssr";
|
||||
|
||||
/**
|
||||
* The default export is the QwikCity adapter used by Vite preview.
|
||||
*/
|
||||
export default createQwikCity({ render, qwikCityPlan });
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* SSR entry point, in all cases the application is rendered outside the browser, this
|
||||
* entry point will be the common one.
|
||||
*
|
||||
* - Server (express, cloudflare...)
|
||||
* - npm run start
|
||||
* - npm run preview
|
||||
* - npm run build
|
||||
*
|
||||
*/
|
||||
import {
|
||||
renderToStream,
|
||||
type RenderToStreamOptions,
|
||||
} from "@builder.io/qwik/server";
|
||||
import Root from "./root";
|
||||
|
||||
export default function (opts: RenderToStreamOptions) {
|
||||
return renderToStream(<Root />, {
|
||||
...opts,
|
||||
// Use container attributes to set attributes on the html tag.
|
||||
containerAttributes: {
|
||||
lang: "en-us",
|
||||
...opts.containerAttributes,
|
||||
},
|
||||
serverData: {
|
||||
...opts.serverData,
|
||||
},
|
||||
});
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* WHAT IS THIS FILE?
|
||||
*
|
||||
* Globally applied styles. No matter which components are in the page or matching route,
|
||||
* the styles in here will be applied to the Document, without any sort of CSS scoping.
|
||||
*
|
||||
*/
|
||||
|
||||
:root {
|
||||
--qwik-dark-blue: #006ce9;
|
||||
--qwik-light-blue: #18b6f6;
|
||||
--qwik-light-purple: #ac7ff4;
|
||||
--qwik-dark-purple: #713fc2;
|
||||
--qwik-dirty-black: #1d2033;
|
||||
--qwik-dark-background: #151934;
|
||||
--qwik-dark-text: #ffffff;
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
font-family:
|
||||
ui-sans-serif,
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
"Helvetica Neue",
|
||||
Arial,
|
||||
"Noto Sans",
|
||||
sans-serif,
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
"Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: inherit;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
|
@ -0,0 +1,33 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import { isDev } from "@builder.io/qwik";
|
||||
import { QwikCityProvider, RouterOutlet } from "@builder.io/qwik-city";
|
||||
import { RouterHead } from "./components/router-head/router-head";
|
||||
|
||||
import "./global.css";
|
||||
|
||||
export default component$(() => {
|
||||
/**
|
||||
* The root of a QwikCity site always start with the <QwikCityProvider> component,
|
||||
* immediately followed by the document's <head> and <body>.
|
||||
*
|
||||
* Don't remove the `<head>` and `<body>` elements.
|
||||
*/
|
||||
|
||||
return (
|
||||
<QwikCityProvider>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
{!isDev && (
|
||||
<link
|
||||
rel="manifest"
|
||||
href={`${import.meta.env.BASE_URL}manifest.json`}
|
||||
/>
|
||||
)}
|
||||
<RouterHead />
|
||||
</head>
|
||||
<body lang="en">
|
||||
<RouterOutlet />
|
||||
</body>
|
||||
</QwikCityProvider>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,77 @@
|
|||
.host {
|
||||
display: grid;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
--rotation: 135deg;
|
||||
--rotation: 225deg;
|
||||
--size-step: 10px;
|
||||
--odd-color-step: 5;
|
||||
--even-color-step: 5;
|
||||
--center: 12;
|
||||
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.square {
|
||||
--size: calc(40px + var(--index) * var(--size-step));
|
||||
|
||||
display: block;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
transform: rotateZ(
|
||||
calc(var(--rotation) * var(--state) * (var(--center) - var(--index)))
|
||||
);
|
||||
transition-property: transform, border-color;
|
||||
transition-duration: 5s;
|
||||
transition-timing-function: ease-in-out;
|
||||
grid-area: 1 / 1;
|
||||
background: white;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
box-sizing: border-box;
|
||||
will-change: transform, border-color;
|
||||
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.square.odd {
|
||||
--luminance: calc(1 - calc(calc(var(--index) * var(--odd-color-step)) / 256));
|
||||
background: rgb(
|
||||
calc(172 * var(--luminance)),
|
||||
calc(127 * var(--luminance)),
|
||||
calc(244 * var(--luminance))
|
||||
);
|
||||
}
|
||||
|
||||
.pride .square:nth-child(12n + 1) {
|
||||
background: #e70000;
|
||||
}
|
||||
.pride .square:nth-child(12n + 3) {
|
||||
background: #ff8c00;
|
||||
}
|
||||
.pride .square:nth-child(12n + 5) {
|
||||
background: #ffef00;
|
||||
}
|
||||
.pride .square:nth-child(12n + 7) {
|
||||
background: #00811f;
|
||||
}
|
||||
.pride .square:nth-child(12n + 9) {
|
||||
background: #0044ff;
|
||||
}
|
||||
.pride .square:nth-child(12n + 11) {
|
||||
background: #760089;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
import {
|
||||
component$,
|
||||
useVisibleTask$,
|
||||
useStore,
|
||||
useStylesScoped$,
|
||||
} from "@builder.io/qwik";
|
||||
import { type DocumentHead, useLocation } from "@builder.io/qwik-city";
|
||||
import styles from "./flower.css?inline";
|
||||
|
||||
export default component$(() => {
|
||||
useStylesScoped$(styles);
|
||||
const loc = useLocation();
|
||||
|
||||
const state = useStore({
|
||||
count: 0,
|
||||
number: 20,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line qwik/no-use-visible-task
|
||||
useVisibleTask$(({ cleanup }) => {
|
||||
const timeout = setTimeout(() => (state.count = 1), 500);
|
||||
cleanup(() => clearTimeout(timeout));
|
||||
|
||||
const internal = setInterval(() => state.count++, 7000);
|
||||
cleanup(() => clearInterval(internal));
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="container container-center">
|
||||
<div role="presentation" class="ellipsis"></div>
|
||||
<h1>
|
||||
<span class="highlight">Generate</span> Flowers
|
||||
</h1>
|
||||
|
||||
<input
|
||||
class="input"
|
||||
type="range"
|
||||
value={state.number}
|
||||
max={50}
|
||||
onInput$={(ev, el) => {
|
||||
state.number = el.valueAsNumber;
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
"--state": `${state.count * 0.1}`,
|
||||
}}
|
||||
class={{
|
||||
host: true,
|
||||
pride: loc.url.searchParams.get("pride") === "true",
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: state.number }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
class={{
|
||||
square: true,
|
||||
odd: i % 2 === 0,
|
||||
}}
|
||||
style={{ "--index": `${i + 1}` }}
|
||||
/>
|
||||
)).reverse()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const head: DocumentHead = {
|
||||
title: "Qwik Flower",
|
||||
};
|
|
@ -0,0 +1,78 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import {
|
||||
type DocumentHead,
|
||||
routeLoader$,
|
||||
routeAction$,
|
||||
zod$,
|
||||
z,
|
||||
Form,
|
||||
} from "@builder.io/qwik-city";
|
||||
import styles from "./todolist.module.css";
|
||||
|
||||
interface ListItem {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export const list: ListItem[] = [];
|
||||
|
||||
export const useListLoader = routeLoader$(() => {
|
||||
return list;
|
||||
});
|
||||
|
||||
export const useAddToListAction = routeAction$(
|
||||
(item) => {
|
||||
list.push(item);
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
},
|
||||
zod$({
|
||||
text: z.string().trim().min(1),
|
||||
}),
|
||||
);
|
||||
|
||||
export default component$(() => {
|
||||
const list = useListLoader();
|
||||
const action = useAddToListAction();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div class="container container-center">
|
||||
<h1>
|
||||
<span class="highlight">TODO</span> List
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div role="presentation" class="ellipsis"></div>
|
||||
|
||||
<div class="container container-center">
|
||||
{list.value.length === 0 ? (
|
||||
<span class={styles.empty}>No items found</span>
|
||||
) : (
|
||||
<ul class={styles.list}>
|
||||
{list.value.map((item, index) => (
|
||||
<li key={`items-${index}`}>{item.text}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="container container-center">
|
||||
<Form action={action} spaReset>
|
||||
<input type="text" name="text" required class={styles.input} />{" "}
|
||||
<button type="submit" class="button-dark">
|
||||
Add item
|
||||
</button>
|
||||
</Form>
|
||||
|
||||
<p class={styles.hint}>
|
||||
PS: This little app works even when JavaScript is disabled.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export const head: DocumentHead = {
|
||||
title: "Qwik Todo List",
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.list,
|
||||
.empty {
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
.list li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: white;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.input {
|
||||
background: white;
|
||||
color: var(--qwik-light-blue);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 15px 20px;
|
||||
margin-right: 10px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 0.8rem;
|
||||
color: white;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.input {
|
||||
padding: 23px 35px;
|
||||
margin-right: 20px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
import { component$ } from "@builder.io/qwik";
|
||||
import type { DocumentHead } from "@builder.io/qwik-city";
|
||||
|
||||
import Counter from "../components/starter/counter/counter";
|
||||
import Hero from "../components/starter/hero/hero";
|
||||
import Infobox from "../components/starter/infobox/infobox";
|
||||
import Starter from "../components/starter/next-steps/next-steps";
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
<Starter />
|
||||
|
||||
<div role="presentation" class="ellipsis"></div>
|
||||
<div role="presentation" class="ellipsis ellipsis-purple"></div>
|
||||
|
||||
<div class="container container-center container-spacing-xl">
|
||||
<h3>
|
||||
You can <span class="highlight">count</span>
|
||||
<br /> on me
|
||||
</h3>
|
||||
<Counter />
|
||||
</div>
|
||||
|
||||
<div class="container container-flex">
|
||||
<Infobox>
|
||||
<div q:slot="title" class="icon icon-cli">
|
||||
CLI Commands
|
||||
</div>
|
||||
<>
|
||||
<p>
|
||||
<code>npm run dev</code>
|
||||
<br />
|
||||
Starts the development server and watches for changes
|
||||
</p>
|
||||
<p>
|
||||
<code>npm run preview</code>
|
||||
<br />
|
||||
Creates production build and starts a server to preview it
|
||||
</p>
|
||||
<p>
|
||||
<code>npm run build</code>
|
||||
<br />
|
||||
Creates production build
|
||||
</p>
|
||||
<p>
|
||||
<code>npm run qwik add</code>
|
||||
<br />
|
||||
Runs the qwik CLI to add integrations
|
||||
</p>
|
||||
</>
|
||||
</Infobox>
|
||||
|
||||
<div>
|
||||
<Infobox>
|
||||
<div q:slot="title" class="icon icon-apps">
|
||||
Example Apps
|
||||
</div>
|
||||
<p>
|
||||
Have a look at the <a href="/demo/flower">Flower App</a> or the{" "}
|
||||
<a href="/demo/todolist">Todo App</a>.
|
||||
</p>
|
||||
</Infobox>
|
||||
|
||||
<Infobox>
|
||||
<div q:slot="title" class="icon icon-community">
|
||||
Community
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<span>Questions or just want to say hi? </span>
|
||||
<a href="https://qwik.dev/chat" target="_blank">
|
||||
Chat on discord!
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>Follow </span>
|
||||
<a href="https://twitter.com/QwikDev" target="_blank">
|
||||
@QwikDev
|
||||
</a>
|
||||
<span> on Twitter</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>Open issues and contribute on </span>
|
||||
<a href="https://github.com/QwikDev/qwik" target="_blank">
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>Watch </span>
|
||||
<a href="https://qwik.dev/media/" target="_blank">
|
||||
Presentations, Podcasts, Videos, etc.
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</Infobox>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export const head: DocumentHead = {
|
||||
title: "Welcome to Qwik",
|
||||
meta: [
|
||||
{
|
||||
name: "description",
|
||||
content: "Qwik site description",
|
||||
},
|
||||
],
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
import { component$, Slot, useStyles$ } from "@builder.io/qwik";
|
||||
import { routeLoader$ } from "@builder.io/qwik-city";
|
||||
|
||||
import Header from "../components/starter/header/header";
|
||||
import Footer from "../components/starter/footer/footer";
|
||||
|
||||
import styles from "./styles.css?inline";
|
||||
|
||||
export const useServerTimeLoader = routeLoader$(() => {
|
||||
return {
|
||||
date: new Date().toISOString(),
|
||||
};
|
||||
});
|
||||
|
||||
export default component$(() => {
|
||||
useStyles$(styles);
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>
|
||||
<Slot />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,214 @@
|
|||
/* THIS FILE IS JUST FOR EXAMPLES, DELETE IT IF YOU DON'T NEED IT */
|
||||
|
||||
/* SHELL ---------------------------------------- */
|
||||
html {
|
||||
font-family:
|
||||
ui-sans-serif,
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
"Helvetica Neue",
|
||||
Arial,
|
||||
"Noto Sans",
|
||||
sans-serif,
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
"Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--qwik-dark-background);
|
||||
color: var(--qwik-dark-text);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* HEADINGS ------------------------------------- */
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
color: white;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2rem;
|
||||
text-align: center;
|
||||
}
|
||||
h1 .highlight,
|
||||
h3 .highlight {
|
||||
color: var(--qwik-light-blue);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 400;
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
h2 .highlight {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
h1 {
|
||||
font-size: 5rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 3.4rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* TAGS ----------------------------------------- */
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--qwik-light-blue);
|
||||
}
|
||||
|
||||
code {
|
||||
background: rgba(230, 230, 230, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
/* CONTAINER ------------------------------------ */
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
padding: 30px 40px;
|
||||
}
|
||||
.container.container-purple {
|
||||
background: var(--qwik-light-purple);
|
||||
}
|
||||
.container.container-dark {
|
||||
background: var(--qwik-dark-background);
|
||||
color: var(--qwik-dark-text);
|
||||
}
|
||||
.container.container-center {
|
||||
text-align: center;
|
||||
}
|
||||
.container.container-flex {
|
||||
/* does nothing on mobile */
|
||||
}
|
||||
.container.container-spacing-xl {
|
||||
padding: 50px 40px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
padding: 60px 80px;
|
||||
}
|
||||
.container.container-spacing-xl {
|
||||
padding: 100px 60px;
|
||||
}
|
||||
.container.container-flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
/* BUTTONS -------------------------------------- */
|
||||
a.button,
|
||||
button {
|
||||
background: var(--qwik-light-blue);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
padding: 15px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a.button.button-dark,
|
||||
button.button-dark {
|
||||
background: var(--qwik-dirty-black);
|
||||
}
|
||||
|
||||
a.button.button-small,
|
||||
button.button-small {
|
||||
padding: 15px 25px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
a.button,
|
||||
button {
|
||||
font-size: 1rem;
|
||||
padding: 23px 35px;
|
||||
}
|
||||
}
|
||||
|
||||
/* DESIGN --------------------------------------- */
|
||||
.ellipsis {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: -100px;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
background: radial-gradient(
|
||||
57.58% 57.58% at 48.79% 42.42%,
|
||||
rgba(24, 180, 244, 0.5) 0%,
|
||||
rgba(46, 55, 114, 0) 63.22%
|
||||
);
|
||||
transform: rotate(5deg);
|
||||
opacity: 0.5;
|
||||
z-index: -1;
|
||||
}
|
||||
.ellipsis.ellipsis-purple {
|
||||
top: 1350px;
|
||||
left: -100px;
|
||||
background: radial-gradient(
|
||||
50% 50% at 50% 50%,
|
||||
rgba(172, 127, 244, 0.5) 0%,
|
||||
rgba(21, 25, 52, 0) 100%
|
||||
);
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.ellipsis {
|
||||
top: -100px;
|
||||
left: 350px;
|
||||
width: 1400px;
|
||||
height: 800px;
|
||||
}
|
||||
.ellipsis.ellipsis-purple {
|
||||
top: 1300px;
|
||||
left: -200px;
|
||||
}
|
||||
}
|
||||
|
||||
/* used icon pack: https://www.svgrepo.com/collection/phosphor-thin-icons */
|
||||
.icon:before {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
margin-right: 20px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.icon-cli:before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg fill='%23ffffff' width='20px' height='20px' viewBox='0 0 256 256' id='Flat' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M122.499 124.87646a4.00053 4.00053 0 0 1 0 6.24708l-40 32a4.0002 4.0002 0 0 1-4.998-6.24708L113.59668 128 77.501 99.12354a4.0002 4.0002 0 0 1 4.998-6.24708ZM175.99414 156h-40a4 4 0 0 0 0 8h40a4 4 0 1 0 0-8ZM228 56.48535v143.0293A12.49909 12.49909 0 0 1 215.51465 212H40.48535A12.49909 12.49909 0 0 1 28 199.51465V56.48535A12.49909 12.49909 0 0 1 40.48535 44h175.0293A12.49909 12.49909 0 0 1 228 56.48535Zm-8 0A4.49023 4.49023 0 0 0 215.51465 52H40.48535A4.49023 4.49023 0 0 0 36 56.48535v143.0293A4.49023 4.49023 0 0 0 40.48535 204h175.0293A4.49023 4.49023 0 0 0 220 199.51465Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.icon-apps:before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg fill='%23ffffff' width='20px' height='20px' viewBox='0 0 256 256' id='Flat' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M216 44.00586H40a12.01375 12.01375 0 0 0-12 12v144a12.01375 12.01375 0 0 0 12 12H216a12.01375 12.01375 0 0 0 12-12v-144A12.01375 12.01375 0 0 0 216 44.00586Zm4 156a4.00458 4.00458 0 0 1-4 4H40a4.00458 4.00458 0 0 1-4-4v-144a4.00458 4.00458 0 0 1 4-4H216a4.00458 4.00458 0 0 1 4 4Zm-144-116a8 8 0 1 1-8-8A7.99977 7.99977 0 0 1 76 84.00586Zm40 0a8 8 0 1 1-8-8A7.99977 7.99977 0 0 1 116 84.00586Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.icon-community:before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg fill='%23ffffff' width='20px' height='20px' viewBox='0 0 256 256' id='Flat' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M246.40381 143.19434a4.00061 4.00061 0 0 1-5.60108-.7959A55.57857 55.57857 0 0 0 196 120a4 4 0 0 1 0-8 28 28 0 1 0-27.50732-33.26074 4.00013 4.00013 0 0 1-7.85987-1.49219 36.00191 36.00191 0 1 1 54.06494 37.50513 63.58068 63.58068 0 0 1 32.50147 22.84155A3.99993 3.99993 0 0 1 246.40381 143.19434Zm-57.24268 71.05273a3.9998 3.9998 0 1 1-7.1914 3.50391 60.02582 60.02582 0 0 0-107.93946 0 3.9998 3.9998 0 1 1-7.1914-3.50391 67.56008 67.56008 0 0 1 40.90625-35.20581 44 44 0 1 1 40.50976 0A67.56139 67.56139 0 0 1 189.16113 214.24707ZM128 176a36 36 0 1 0-36-36A36.04061 36.04061 0 0 0 128 176ZM60 112A28 28 0 1 1 87.50732 78.73828a3.99989 3.99989 0 1 0 7.85938-1.49219A36.00177 36.00177 0 1 0 41.30225 114.7522 63.5829 63.5829 0 0 0 8.79883 137.5957a4 4 0 1 0 6.39648 4.80469A55.58072 55.58072 0 0 1 60 120a4 4 0 0 0 0-8Z'/%3E%3C/svg%3E");
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"target": "ES2017",
|
||||
"module": "ES2022",
|
||||
"lib": ["es2022", "DOM", "WebWorker", "DOM.Iterable"],
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@builder.io/qwik",
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "Bundler",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": true,
|
||||
"isolatedModules": true,
|
||||
"outDir": "tmp",
|
||||
"noEmit": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
},
|
||||
/* if you do not use CSS modules, remove this line and delete the typescript-plugin-css-modules module from package.json */
|
||||
"plugins": [
|
||||
{
|
||||
"name": "typescript-plugin-css-modules"
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
"@cloudflare/workers-types/2023-07-01",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": ["src", "./*.d.ts", "./*.config.ts"]
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* This is the base config for vite.
|
||||
* When building, the adapter config is used which loads this file and extends it.
|
||||
*/
|
||||
import { defineConfig, type UserConfig } from "vite";
|
||||
import { qwikVite } from "@builder.io/qwik/optimizer";
|
||||
import { qwikCity } from "@builder.io/qwik-city/vite";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import pkg from "./package.json";
|
||||
|
||||
let platform = {};
|
||||
|
||||
if(process.env.NODE_ENV === 'development') {
|
||||
const { getPlatformProxy } = await import('wrangler');
|
||||
platform = await getPlatformProxy();
|
||||
}
|
||||
|
||||
type PkgDep = Record<string, string>;
|
||||
const { dependencies = {}, devDependencies = {} } = pkg as any as {
|
||||
dependencies: PkgDep;
|
||||
devDependencies: PkgDep;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
errorOnDuplicatesPkgDeps(devDependencies, dependencies);
|
||||
|
||||
/**
|
||||
* Note that Vite normally starts from `index.html` but the qwikCity plugin makes start at `src/entry.ssr.tsx` instead.
|
||||
*/
|
||||
export default defineConfig(({ command, mode }): UserConfig => {
|
||||
return {
|
||||
plugins: [qwikCity({
|
||||
platform
|
||||
}), qwikVite(), tsconfigPaths({ root: "." })],
|
||||
// This tells Vite which dependencies to pre-build in dev mode.
|
||||
optimizeDeps: {
|
||||
// Put problematic deps that break bundling here, mostly those with binaries.
|
||||
// For example ['better-sqlite3'] if you use that in server functions.
|
||||
exclude: [],
|
||||
},
|
||||
|
||||
/**
|
||||
* This is an advanced setting. It improves the bundling of your server code. To use it, make sure you understand when your consumed packages are dependencies or dev dependencies. (otherwise things will break in production)
|
||||
*/
|
||||
// ssr:
|
||||
// command === "build" && mode === "production"
|
||||
// ? {
|
||||
// // All dev dependencies should be bundled in the server build
|
||||
// noExternal: Object.keys(devDependencies),
|
||||
// // Anything marked as a dependency will not be bundled
|
||||
// // These should only be production binary deps (including deps of deps), CLI deps, and their module graph
|
||||
// // If a dep-of-dep needs to be external, add it here
|
||||
// // For example, if something uses `bcrypt` but you don't have it as a dep, you can write
|
||||
// // external: [...Object.keys(dependencies), 'bcrypt']
|
||||
// external: Object.keys(dependencies),
|
||||
// }
|
||||
// : undefined,
|
||||
|
||||
server: {
|
||||
headers: {
|
||||
// Don't cache the server response in dev mode
|
||||
"Cache-Control": "public, max-age=0",
|
||||
},
|
||||
},
|
||||
preview: {
|
||||
headers: {
|
||||
// Do cache the server response in preview (non-adapter production build)
|
||||
"Cache-Control": "public, max-age=600",
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// *** utils ***
|
||||
|
||||
/**
|
||||
* Function to identify duplicate dependencies and throw an error
|
||||
* @param {Object} devDependencies - List of development dependencies
|
||||
* @param {Object} dependencies - List of production dependencies
|
||||
*/
|
||||
function errorOnDuplicatesPkgDeps(
|
||||
devDependencies: PkgDep,
|
||||
dependencies: PkgDep,
|
||||
) {
|
||||
let msg = "";
|
||||
// Create an array 'duplicateDeps' by filtering devDependencies.
|
||||
// If a dependency also exists in dependencies, it is considered a duplicate.
|
||||
const duplicateDeps = Object.keys(devDependencies).filter(
|
||||
(dep) => dependencies[dep],
|
||||
);
|
||||
|
||||
// include any known qwik packages
|
||||
const qwikPkg = Object.keys(dependencies).filter((value) =>
|
||||
/qwik/i.test(value),
|
||||
);
|
||||
|
||||
// any errors for missing "qwik-city-plan"
|
||||
// [PLUGIN_ERROR]: Invalid module "@qwik-city-plan" is not a valid package
|
||||
msg = `Move qwik packages ${qwikPkg.join(", ")} to devDependencies`;
|
||||
|
||||
if (qwikPkg.length > 0) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
// Format the error message with the duplicates list.
|
||||
// The `join` function is used to represent the elements of the 'duplicateDeps' array as a comma-separated string.
|
||||
msg = `
|
||||
Warning: The dependency "${duplicateDeps.join(", ")}" is listed in both "devDependencies" and "dependencies".
|
||||
Please move the duplicated dependencies to "devDependencies" only and remove it from "dependencies"
|
||||
`;
|
||||
|
||||
// Throw an error with the constructed message.
|
||||
if (duplicateDeps.length > 0) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// Generated by Wrangler
|
||||
// After adding bindings to `wrangler.jsonc`, regenerate this interface via `npm run cf-typegen`
|
||||
interface Env {
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* For more details on how to configure Wrangler, refer to:
|
||||
* https://developers.cloudflare.com/workers/wrangler/configuration/
|
||||
*/
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "dutylog",
|
||||
"main": "./dist/_worker.js",
|
||||
"compatibility_date": "2025-08-16",
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat",
|
||||
"global_fetch_strictly_public"
|
||||
],
|
||||
"assets": {
|
||||
"binding": "ASSET",
|
||||
"directory": "./dist"
|
||||
},
|
||||
"observability": {
|
||||
"enabled": true
|
||||
}
|
||||
/**
|
||||
* Smart Placement
|
||||
* Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement
|
||||
*/
|
||||
// "placement": { "mode": "smart" }
|
||||
/**
|
||||
* Bindings
|
||||
* Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform, including
|
||||
* databases, object storage, AI inference, real-time communication and more.
|
||||
* https://developers.cloudflare.com/workers/runtime-apis/bindings/
|
||||
*/
|
||||
/**
|
||||
* Environment Variables
|
||||
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
|
||||
*/
|
||||
// "vars": { "MY_VARIABLE": "production_value" }
|
||||
/**
|
||||
* Note: Use secrets to store sensitive data.
|
||||
* https://developers.cloudflare.com/workers/configuration/secrets/
|
||||
*/
|
||||
/**
|
||||
* Static Assets
|
||||
* https://developers.cloudflare.com/workers/static-assets/binding/
|
||||
*/
|
||||
// "assets": { "directory": "./public/", "binding": "ASSETS" }
|
||||
/**
|
||||
* Service Bindings (communicate between multiple Workers)
|
||||
* https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings
|
||||
*/
|
||||
// "services": [{ "binding": "MY_SERVICE", "service": "my-service" }]
|
||||
}
|
Loading…
Reference in New Issue