create-qwik 0.0.38 → 0.0.39-dev20220722190315
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/starters/apps/base/package.json +6 -6
- package/starters/apps/qwik-city/package.json +1 -1
- package/starters/apps/qwik-city/src/components/breadcrumbs/breadcrumbs.css +25 -0
- package/starters/apps/qwik-city/src/components/breadcrumbs/breadcrumbs.tsx +77 -0
- package/starters/apps/qwik-city/src/components/footer/footer.css +1 -1
- package/starters/apps/qwik-city/src/components/footer/footer.tsx +3 -1
- package/starters/apps/qwik-city/src/components/header/header.css +10 -1
- package/starters/apps/qwik-city/src/components/header/header.tsx +24 -32
- package/starters/apps/qwik-city/src/components/menu/menu.css +10 -0
- package/starters/apps/qwik-city/src/components/menu/menu.tsx +3 -3
- package/starters/apps/qwik-city/src/global.css +21 -12
- package/starters/apps/qwik-city/src/routes/about-us.tsx +2 -4
- package/starters/apps/qwik-city/src/routes/api/[org]/[user].json/index.ts +12 -23
- package/starters/apps/qwik-city/src/routes/api/_layout-foo/index.tsx +16 -22
- package/starters/apps/qwik-city/src/routes/api/data.json.ts +6 -9
- package/starters/apps/qwik-city/src/routes/api/index@foo.tsx +7 -4
- package/starters/apps/qwik-city/src/routes/blog/[...slug].tsx +28 -5
- package/starters/apps/qwik-city/src/routes/blog/_layout/index.tsx +2 -2
- package/starters/apps/qwik-city/src/routes/dashboard/index.tsx +8 -0
- package/starters/apps/qwik-city/src/routes/docs/[category]/[id]/index.tsx +14 -6
- package/starters/apps/qwik-city/src/routes/docs/{_layout/docs.css → _layout!/index.css} +2 -1
- package/starters/apps/qwik-city/src/routes/docs/_layout!/index.tsx +31 -0
- package/starters/apps/qwik-city/src/routes/docs/_menu.md +4 -2
- package/starters/apps/qwik-city/src/routes/docs/getting-started.md +44 -0
- package/starters/apps/qwik-city/src/routes/docs/index.tsx +2 -4
- package/starters/apps/qwik-city/src/routes/docs/{introduction → overview}/index.md +2 -2
- package/starters/apps/qwik-city/src/routes/index.tsx +6 -1
- package/starters/apps/qwik-city/src/routes/products/[id].tsx +132 -0
- package/starters/features/react/package.json +1 -1
- package/starters/servers/express/package.json +1 -1
- package/starters/apps/qwik-city/src/routes/__auth/_layout.tsx +0 -17
- package/starters/apps/qwik-city/src/routes/__auth/sign-in.tsx +0 -25
- package/starters/apps/qwik-city/src/routes/__auth/sign-up.tsx +0 -29
- package/starters/apps/qwik-city/src/routes/docs/_layout/index.tsx +0 -23
- package/starters/apps/qwik-city/src/routes/docs/getting-started.mdx +0 -32
package/package.json
CHANGED
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
"typecheck": "tsc --incremental --noEmit"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@builder.io/qwik": "0.0.
|
|
18
|
+
"@builder.io/qwik": "0.0.39-dev20220722190315",
|
|
19
19
|
"@types/eslint": "8.4.5",
|
|
20
20
|
"@types/node": "latest",
|
|
21
|
-
"@typescript-eslint/eslint-plugin": "5.30.
|
|
22
|
-
"@typescript-eslint/parser": "5.30.
|
|
23
|
-
"eslint-plugin-qwik": "0.0.
|
|
21
|
+
"@typescript-eslint/eslint-plugin": "5.30.7",
|
|
22
|
+
"@typescript-eslint/parser": "5.30.7",
|
|
23
|
+
"eslint-plugin-qwik": "0.0.39-dev20220722190315",
|
|
24
24
|
"eslint": "8.20.0",
|
|
25
|
-
"node-fetch": "3.2.
|
|
25
|
+
"node-fetch": "3.2.9",
|
|
26
26
|
"typescript": "4.7.4",
|
|
27
|
-
"vite": "3.0.
|
|
27
|
+
"vite": "3.0.2"
|
|
28
28
|
},
|
|
29
29
|
"type": "module",
|
|
30
30
|
"homepage": "https://qwik.builder.io/",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
nav.breadcrumbs {
|
|
2
|
+
padding: 5px;
|
|
3
|
+
border-bottom: 1px solid #ddd;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
nav.breadcrumbs > span {
|
|
7
|
+
display: inline-block;
|
|
8
|
+
padding: 5px 0;
|
|
9
|
+
font-size: 12px;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
nav.breadcrumbs > span a {
|
|
13
|
+
text-decoration: none;
|
|
14
|
+
color: inherit;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
nav.breadcrumbs > span::after {
|
|
18
|
+
content: '>';
|
|
19
|
+
padding: 0 5px;
|
|
20
|
+
opacity: 0.4;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
nav.breadcrumbs > span:last-child::after {
|
|
24
|
+
display: none;
|
|
25
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { component$, Host, useScopedStyles$ } from '@builder.io/qwik';
|
|
2
|
+
import { useContent, useLocation, ContentMenu } from '@builder.io/qwik-city';
|
|
3
|
+
import styles from './breadcrumbs.css?inline';
|
|
4
|
+
|
|
5
|
+
export const Breadcrumbs = component$(
|
|
6
|
+
() => {
|
|
7
|
+
useScopedStyles$(styles);
|
|
8
|
+
|
|
9
|
+
const { menu } = useContent();
|
|
10
|
+
const loc = useLocation();
|
|
11
|
+
|
|
12
|
+
const breadcrumbs = createBreadcrumbs(menu, loc.pathname);
|
|
13
|
+
if (breadcrumbs.length === 0) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Host class="breadcrumbs">
|
|
19
|
+
{breadcrumbs.map((b) => (
|
|
20
|
+
<span>{b.href ? <a href={b.href}>{b.text}</a> : b.text}</span>
|
|
21
|
+
))}
|
|
22
|
+
</Host>
|
|
23
|
+
);
|
|
24
|
+
},
|
|
25
|
+
{ tagName: 'nav' }
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export function createBreadcrumbs(menu: ContentMenu | undefined, pathname: string) {
|
|
29
|
+
if (menu?.items) {
|
|
30
|
+
for (const indexA of menu.items) {
|
|
31
|
+
const breadcrumbA: ContentBreadcrumb = {
|
|
32
|
+
text: indexA.text,
|
|
33
|
+
};
|
|
34
|
+
if (typeof indexA.href === 'string') {
|
|
35
|
+
breadcrumbA.href = indexA.href;
|
|
36
|
+
}
|
|
37
|
+
if (indexA.href === pathname) {
|
|
38
|
+
return [breadcrumbA];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (indexA.items) {
|
|
42
|
+
for (const indexB of indexA.items) {
|
|
43
|
+
const breadcrumbB: ContentBreadcrumb = {
|
|
44
|
+
text: indexB.text,
|
|
45
|
+
};
|
|
46
|
+
if (typeof indexB.href === 'string') {
|
|
47
|
+
breadcrumbB.href = indexB.href;
|
|
48
|
+
}
|
|
49
|
+
if (indexB.href === pathname) {
|
|
50
|
+
return [breadcrumbA, breadcrumbB];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (indexB.items) {
|
|
54
|
+
for (const indexC of indexB.items) {
|
|
55
|
+
const breadcrumbC: ContentBreadcrumb = {
|
|
56
|
+
text: indexC.text,
|
|
57
|
+
};
|
|
58
|
+
if (typeof indexC.href === 'string') {
|
|
59
|
+
breadcrumbC.href = indexC.href;
|
|
60
|
+
}
|
|
61
|
+
if (indexC.href === pathname) {
|
|
62
|
+
return [breadcrumbA, breadcrumbB, breadcrumbC];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ContentBreadcrumb {
|
|
75
|
+
text: string;
|
|
76
|
+
href?: string;
|
|
77
|
+
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
header {
|
|
2
|
+
background-color: #0093ee;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
header .header-inner {
|
|
2
6
|
display: grid;
|
|
3
7
|
grid-template-columns: 1fr auto auto;
|
|
4
8
|
padding: 10px;
|
|
5
|
-
|
|
9
|
+
max-width: 800px;
|
|
10
|
+
margin: 0 auto;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.full-screen header .header-inner {
|
|
14
|
+
max-width: 100%;
|
|
6
15
|
}
|
|
7
16
|
|
|
8
17
|
header a {
|
|
@@ -3,43 +3,35 @@ import { useLocation } from '@builder.io/qwik-city';
|
|
|
3
3
|
import styles from './header.css?inline';
|
|
4
4
|
|
|
5
5
|
export default component$(
|
|
6
|
-
(
|
|
6
|
+
() => {
|
|
7
7
|
useStyles$(styles);
|
|
8
8
|
|
|
9
9
|
const pathname = useLocation().pathname;
|
|
10
10
|
|
|
11
11
|
return (
|
|
12
|
-
<Host
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
onClick$={() => {
|
|
36
|
-
if (themeCtx.theme === 'light') {
|
|
37
|
-
themeCtx.theme = 'dark';
|
|
38
|
-
} else {
|
|
39
|
-
themeCtx.theme = 'light';
|
|
40
|
-
}
|
|
41
|
-
}}
|
|
42
|
-
/> */}
|
|
12
|
+
<Host>
|
|
13
|
+
<div class="header-inner">
|
|
14
|
+
<section class="logo">
|
|
15
|
+
<a href="/">Qwik City 🏙</a>
|
|
16
|
+
</section>
|
|
17
|
+
<nav>
|
|
18
|
+
<a href="/blog" class={{ active: pathname.startsWith('/blog') }}>
|
|
19
|
+
Blog
|
|
20
|
+
</a>
|
|
21
|
+
<a href="/docs" class={{ active: pathname.startsWith('/docs') }}>
|
|
22
|
+
Docs
|
|
23
|
+
</a>
|
|
24
|
+
<a href="/api" class={{ active: pathname.startsWith('/api') }}>
|
|
25
|
+
API
|
|
26
|
+
</a>
|
|
27
|
+
<a href="/products/hat" class={{ active: pathname.startsWith('/products') }}>
|
|
28
|
+
Products
|
|
29
|
+
</a>
|
|
30
|
+
<a href="/about-us" class={{ active: pathname.startsWith('/about-us') }}>
|
|
31
|
+
About Us
|
|
32
|
+
</a>
|
|
33
|
+
</nav>
|
|
34
|
+
</div>
|
|
43
35
|
</Host>
|
|
44
36
|
);
|
|
45
37
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { component$, Host, useScopedStyles$ } from '@builder.io/qwik';
|
|
2
|
-
import { useContent, useLocation } from '@builder.io/qwik-city';
|
|
2
|
+
import { useContent, Link, useLocation } from '@builder.io/qwik-city';
|
|
3
3
|
import styles from './menu.css?inline';
|
|
4
4
|
|
|
5
5
|
export const Menu = component$(
|
|
@@ -18,14 +18,14 @@ export const Menu = component$(
|
|
|
18
18
|
<ul>
|
|
19
19
|
{item.items?.map((item) => (
|
|
20
20
|
<li>
|
|
21
|
-
<
|
|
21
|
+
<Link
|
|
22
22
|
href={item.href}
|
|
23
23
|
class={{
|
|
24
24
|
'is-active': loc.pathname === item.href,
|
|
25
25
|
}}
|
|
26
26
|
>
|
|
27
27
|
{item.text}
|
|
28
|
-
</
|
|
28
|
+
</Link>
|
|
29
29
|
</li>
|
|
30
30
|
))}
|
|
31
31
|
</ul>
|
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
html {
|
|
2
|
-
line-height: 1.5;
|
|
3
|
-
-webkit-text-size-adjust: 100%;
|
|
4
|
-
-moz-tab-size: 4;
|
|
5
|
-
-o-tab-size: 4;
|
|
6
|
-
tab-size: 4;
|
|
7
|
-
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
8
|
-
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
|
9
|
-
'Segoe UI Symbol', 'Noto Color Emoji';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
1
|
body {
|
|
2
|
+
margin: 0;
|
|
13
3
|
padding: 0;
|
|
14
|
-
|
|
4
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
|
|
5
|
+
sans-serif;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
main {
|
|
9
|
+
padding: 10px 20px;
|
|
10
|
+
max-width: 800px;
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.full-screen main {
|
|
15
|
+
max-width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
a {
|
|
19
|
+
color: #006eb3;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
a:hover {
|
|
23
|
+
text-decoration: none;
|
|
15
24
|
}
|
|
@@ -3,30 +3,19 @@ import os from 'os';
|
|
|
3
3
|
|
|
4
4
|
export const onGet: EndpointHandler = ({ request, params }) => {
|
|
5
5
|
return {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
arch: os.arch(),
|
|
14
|
-
node: process.versions.node,
|
|
15
|
-
},
|
|
6
|
+
timestamp: Date.now(),
|
|
7
|
+
method: request.method,
|
|
8
|
+
url: request.url,
|
|
9
|
+
params,
|
|
10
|
+
os: os.platform(),
|
|
11
|
+
arch: os.arch(),
|
|
12
|
+
node: process.versions.node,
|
|
16
13
|
};
|
|
17
14
|
};
|
|
18
15
|
|
|
19
|
-
export const onPost: EndpointHandler = async ({ request,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
method: request.method,
|
|
25
|
-
url: request.url,
|
|
26
|
-
params,
|
|
27
|
-
os: os.platform(),
|
|
28
|
-
arch: os.arch(),
|
|
29
|
-
node: process.versions.node,
|
|
30
|
-
},
|
|
31
|
-
};
|
|
16
|
+
export const onPost: EndpointHandler = async ({ request, response }) => {
|
|
17
|
+
response.headers.set('Content-Type', 'text/plain');
|
|
18
|
+
return `Platform: ${os.platform()}, Node: ${process.versions.node}, HTTP Method: ${
|
|
19
|
+
request.method
|
|
20
|
+
}`;
|
|
32
21
|
};
|
|
@@ -1,38 +1,32 @@
|
|
|
1
1
|
import { component$, Host, Slot, useScopedStyles$ } from '@builder.io/qwik';
|
|
2
2
|
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
3
|
-
import Footer from '../../../components/footer/footer';
|
|
4
|
-
import Header from '../../../components/header/header';
|
|
5
3
|
import styles from './api.css?inline';
|
|
6
4
|
|
|
7
5
|
export default component$(() => {
|
|
8
6
|
useScopedStyles$(styles);
|
|
9
7
|
|
|
10
8
|
return (
|
|
11
|
-
<Host>
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
</
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<Slot />
|
|
27
|
-
</section>
|
|
28
|
-
</main>
|
|
29
|
-
<Footer />
|
|
9
|
+
<Host class="api">
|
|
10
|
+
<aside class="api-menu">
|
|
11
|
+
<h2>API</h2>
|
|
12
|
+
<ul>
|
|
13
|
+
<li>
|
|
14
|
+
<a href="/api/builder.io/oss.json">Org/User</a>
|
|
15
|
+
</li>
|
|
16
|
+
<li>
|
|
17
|
+
<a href="/api/data.json">Data</a>
|
|
18
|
+
</li>
|
|
19
|
+
</ul>
|
|
20
|
+
</aside>
|
|
21
|
+
<section class="api-content">
|
|
22
|
+
<Slot />
|
|
23
|
+
</section>
|
|
30
24
|
</Host>
|
|
31
25
|
);
|
|
32
26
|
});
|
|
33
27
|
|
|
34
28
|
export const head: DocumentHead = ({ pathname }) => {
|
|
35
29
|
return {
|
|
36
|
-
title: pathname
|
|
30
|
+
title: `API: ${pathname}`,
|
|
37
31
|
};
|
|
38
32
|
};
|
|
@@ -3,14 +3,11 @@ import os from 'os';
|
|
|
3
3
|
|
|
4
4
|
export const onGet: EndpointHandler = ({ request }) => {
|
|
5
5
|
return {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
arch: os.arch(),
|
|
13
|
-
node: process.versions.node,
|
|
14
|
-
},
|
|
6
|
+
timestamp: Date.now(),
|
|
7
|
+
method: request.method,
|
|
8
|
+
url: request.url,
|
|
9
|
+
os: os.platform(),
|
|
10
|
+
arch: os.arch(),
|
|
11
|
+
node: process.versions.node,
|
|
15
12
|
};
|
|
16
13
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { component$, Host, useClientEffect$, useStore } from '@builder.io/qwik';
|
|
2
2
|
|
|
3
3
|
export default component$(() => {
|
|
4
|
-
const store = useStore({ timestamp:
|
|
4
|
+
const store = useStore({ timestamp: '', os: '', arch: '', node: '' });
|
|
5
5
|
|
|
6
6
|
useClientEffect$(async () => {
|
|
7
7
|
const url = `/api/builder.io/oss.json`;
|
|
@@ -28,9 +28,12 @@ export default component$(() => {
|
|
|
28
28
|
</ul>
|
|
29
29
|
|
|
30
30
|
<p>Timestamp: {store.timestamp}</p>
|
|
31
|
-
<p>
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
<p>
|
|
32
|
+
Node: <span>{store.node}</span>
|
|
33
|
+
</p>
|
|
34
|
+
<p>
|
|
35
|
+
OS: <span>{store.os}</span>
|
|
36
|
+
</p>
|
|
34
37
|
</Host>
|
|
35
38
|
);
|
|
36
39
|
});
|
|
@@ -1,13 +1,36 @@
|
|
|
1
|
-
import { component$, Host } from '@builder.io/qwik';
|
|
2
|
-
import {
|
|
1
|
+
import { component$, Host, Resource } from '@builder.io/qwik';
|
|
2
|
+
import { useEndpoint, DocumentHead, EndpointHandler } from '@builder.io/qwik-city';
|
|
3
3
|
|
|
4
4
|
export default component$(() => {
|
|
5
|
-
const
|
|
5
|
+
const resource = useEndpoint<EndpointData>();
|
|
6
6
|
|
|
7
7
|
return (
|
|
8
8
|
<Host>
|
|
9
|
-
<
|
|
10
|
-
|
|
9
|
+
<Resource
|
|
10
|
+
resource={resource}
|
|
11
|
+
onResolved={(blog) => (
|
|
12
|
+
<>
|
|
13
|
+
<h1>{blog.blogTitle}</h1>
|
|
14
|
+
<p>{blog.blogContent}</p>
|
|
15
|
+
</>
|
|
16
|
+
)}
|
|
17
|
+
/>
|
|
11
18
|
</Host>
|
|
12
19
|
);
|
|
13
20
|
});
|
|
21
|
+
|
|
22
|
+
export const onGet: EndpointHandler<EndpointData> = async ({ params, request }) => {
|
|
23
|
+
return {
|
|
24
|
+
blogTitle: `Blog: ${params.slug}`,
|
|
25
|
+
blogContent: `${params.slug}, ${request.url}`,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const head: DocumentHead<EndpointData> = ({ data }) => {
|
|
30
|
+
return { title: data?.blogTitle };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export interface EndpointData {
|
|
34
|
+
blogTitle: string;
|
|
35
|
+
blogContent: string;
|
|
36
|
+
}
|
|
@@ -9,10 +9,10 @@ export default component$(() => {
|
|
|
9
9
|
<aside class="blog-menu">
|
|
10
10
|
<ul>
|
|
11
11
|
<li>
|
|
12
|
-
<a href="/blog/
|
|
12
|
+
<a href="/blog/what-is-resumability">What Is Resumability?</a>
|
|
13
13
|
</li>
|
|
14
14
|
<li>
|
|
15
|
-
<a href="/blog/
|
|
15
|
+
<a href="/blog/serializing-props">Serializing Props</a>
|
|
16
16
|
</li>
|
|
17
17
|
</ul>
|
|
18
18
|
</aside>
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { component$, Host } from '@builder.io/qwik';
|
|
2
|
+
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
2
3
|
|
|
3
4
|
export default component$(() => {
|
|
4
5
|
return (
|
|
5
6
|
<Host>
|
|
6
7
|
<h1>Dashboard</h1>
|
|
8
|
+
<p>
|
|
9
|
+
<a href="/sign-out">Sign Out</a>
|
|
10
|
+
</p>
|
|
7
11
|
</Host>
|
|
8
12
|
);
|
|
9
13
|
});
|
|
14
|
+
|
|
15
|
+
export const head: DocumentHead = {
|
|
16
|
+
title: 'Dashboard',
|
|
17
|
+
};
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { component$, Host } from '@builder.io/qwik';
|
|
2
|
-
import { useLocation } from '@builder.io/qwik-city';
|
|
2
|
+
import { useLocation, DocumentHead } from '@builder.io/qwik-city';
|
|
3
3
|
|
|
4
4
|
export default component$(() => {
|
|
5
|
-
const
|
|
5
|
+
const { pathname, params } = useLocation();
|
|
6
6
|
|
|
7
7
|
return (
|
|
8
8
|
<Host>
|
|
9
|
-
<h1>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<p>
|
|
9
|
+
<h1>
|
|
10
|
+
Docs: {params.category} {params.id}
|
|
11
|
+
</h1>
|
|
12
|
+
<p>pathname: {pathname}</p>
|
|
13
|
+
<p>category: {params.category}</p>
|
|
14
|
+
<p>id: {params.id}</p>
|
|
13
15
|
</Host>
|
|
14
16
|
);
|
|
15
17
|
});
|
|
18
|
+
|
|
19
|
+
export const head: DocumentHead = ({ params }) => {
|
|
20
|
+
return {
|
|
21
|
+
title: `${params.category} ${params.id}`,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { component$, Host, Slot, useStyles$ } from '@builder.io/qwik';
|
|
2
|
+
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
3
|
+
import { Breadcrumbs } from '../../../components/breadcrumbs/breadcrumbs';
|
|
4
|
+
import Footer from '../../../components/footer/footer';
|
|
5
|
+
import Header from '../../../components/header/header';
|
|
6
|
+
import { Menu } from '../../../components/menu/menu';
|
|
7
|
+
import styles from './index.css?inline';
|
|
8
|
+
|
|
9
|
+
export default component$(() => {
|
|
10
|
+
useStyles$(styles);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Host class="docs full-screen">
|
|
14
|
+
<Header />
|
|
15
|
+
<main>
|
|
16
|
+
<Menu />
|
|
17
|
+
<section class="docs-content">
|
|
18
|
+
<Breadcrumbs />
|
|
19
|
+
<Slot />
|
|
20
|
+
<Footer />
|
|
21
|
+
</section>
|
|
22
|
+
</main>
|
|
23
|
+
</Host>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const head: DocumentHead = ({ head }) => {
|
|
28
|
+
return {
|
|
29
|
+
title: `Docs: ${head.title}`,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# Docs
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Introduction
|
|
4
4
|
|
|
5
|
-
- [
|
|
5
|
+
- [Overview](overview/index.md)
|
|
6
|
+
- [Getting Started](getting-started.md)
|
|
6
7
|
|
|
7
8
|
## Components
|
|
8
9
|
|
|
9
10
|
- [Basics](/docs/components/basics)
|
|
11
|
+
- [Listeners](/docs/components/listeners)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Getting Started
|
|
6
|
+
|
|
7
|
+
## Creating an app using the CLI
|
|
8
|
+
|
|
9
|
+
The first step is to create an application. Qwik comes with a CLI that allows you to create a basic working skeleton of an application. We will use the CLI to create a Todo sample app, and we will use that application to do a walk-through of Qwik so that you can familiarize yourself with it.
|
|
10
|
+
|
|
11
|
+
## Running in development
|
|
12
|
+
|
|
13
|
+
Once the application is download.
|
|
14
|
+
|
|
15
|
+
1. Change into the directory created by the `npm create qwik@latest`.
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
cd qwik-todo
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
2. Install NPM modules:
|
|
22
|
+
|
|
23
|
+
```shell
|
|
24
|
+
npm install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. Invoke the dev server
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
npm start
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
4. You should see a server running with your To-do application
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
vite v2.8.6 dev server running at:
|
|
37
|
+
|
|
38
|
+
> Local: http://localhost:3000/
|
|
39
|
+
> Network: use `--host` to expose
|
|
40
|
+
|
|
41
|
+
ready in 157ms.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
5. Visit http://localhost:3000/ to explore the To-do app.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: Overview
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Overview
|
|
6
6
|
|
|
7
7
|
Qwik is a new kind of web framework that can deliver instant loading web applications at any size or complexity. Your sites and apps can boot with less than 1kb of JS (_including_ your code, regardless of complexity), and achieve unheard of performance at scale.
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { component$, Host } from '@builder.io/qwik';
|
|
2
|
+
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
2
3
|
|
|
3
4
|
export default component$(() => {
|
|
4
5
|
return (
|
|
5
6
|
<Host>
|
|
6
|
-
<h1>Welcome to
|
|
7
|
+
<h1 onClick$={() => console.warn('hola')}>Welcome to Qwik City</h1>
|
|
7
8
|
|
|
8
9
|
<p>The meta-framework for Qwik.</p>
|
|
9
10
|
</Host>
|
|
10
11
|
);
|
|
11
12
|
});
|
|
13
|
+
|
|
14
|
+
export const head: DocumentHead = {
|
|
15
|
+
title: 'Welcome to Qwik City',
|
|
16
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Resource, component$, Host, useStore } from '@builder.io/qwik';
|
|
2
|
+
import { useEndpoint, useLocation, EndpointHandler, DocumentHead } from '@builder.io/qwik-city';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
|
|
5
|
+
export default component$(() => {
|
|
6
|
+
const { params, pathname } = useLocation();
|
|
7
|
+
const store = useStore({ productFetchData: '' });
|
|
8
|
+
|
|
9
|
+
const resource = useEndpoint<EndpointData>();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Host>
|
|
13
|
+
<Resource
|
|
14
|
+
resource={resource}
|
|
15
|
+
onPending={() => <p>Loading</p>}
|
|
16
|
+
onResolved={(product) => {
|
|
17
|
+
if (product == null) {
|
|
18
|
+
return <h1>Product "{params.id}" not found</h1>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<h1>Product: {product.productId}</h1>
|
|
24
|
+
<p>Price: {product.price}</p>
|
|
25
|
+
<p>{product.description}</p>
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
|
|
31
|
+
<p>(Artificial response delay of 250ms)</p>
|
|
32
|
+
|
|
33
|
+
<p>
|
|
34
|
+
<button
|
|
35
|
+
onClick$={async () => {
|
|
36
|
+
const rsp = await fetch(pathname, {
|
|
37
|
+
headers: { accept: 'application/json' },
|
|
38
|
+
});
|
|
39
|
+
store.productFetchData = JSON.stringify(await rsp.json(), null, 2);
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
fetch("{pathname}") data
|
|
43
|
+
</button>
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<pre>
|
|
47
|
+
<code>{store.productFetchData}</code>
|
|
48
|
+
</pre>
|
|
49
|
+
|
|
50
|
+
<hr />
|
|
51
|
+
|
|
52
|
+
<ul>
|
|
53
|
+
<li>
|
|
54
|
+
<a href="/products/jacket">Jacket</a>
|
|
55
|
+
</li>
|
|
56
|
+
<li>
|
|
57
|
+
<a href="/products/hat">Hat</a>
|
|
58
|
+
</li>
|
|
59
|
+
<li>
|
|
60
|
+
<a href="/products/shirt">T-Shirt (Redirect to /products/tshirt)</a>
|
|
61
|
+
</li>
|
|
62
|
+
<li>
|
|
63
|
+
<a href="/products/hoodie">Hoodie (404 Not Found)</a>
|
|
64
|
+
</li>
|
|
65
|
+
</ul>
|
|
66
|
+
</Host>
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const head: DocumentHead<ProductData | null> = ({ data }) => {
|
|
71
|
+
if (!data) {
|
|
72
|
+
return {
|
|
73
|
+
title: 'Product Not Found',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
title: `Product ${data.productId}, ${data.price}`,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const onGet: EndpointHandler<EndpointData> = async ({ params, response }) => {
|
|
83
|
+
// Serverside Endpoint
|
|
84
|
+
// During SSR, this method is called directly on the server and returns the data object
|
|
85
|
+
// On the client, this same data can be requested with fetch() at the same URL, but also
|
|
86
|
+
// requires the "accept: application/json" request header.
|
|
87
|
+
|
|
88
|
+
// artificial slow response
|
|
89
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 250));
|
|
90
|
+
|
|
91
|
+
if (params.id === 'shirt') {
|
|
92
|
+
// Redirect, which will skip any rendering and the server will immediately redirect
|
|
93
|
+
response.redirect('/products/tshirt');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const productPrice = PRODUCT_DB[params.id];
|
|
98
|
+
|
|
99
|
+
if (!productPrice) {
|
|
100
|
+
// Product data not found
|
|
101
|
+
// but the data is still given to the renderer to decide what to do
|
|
102
|
+
response.status(404);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Found the product data
|
|
107
|
+
// This same data is passed to the head() function
|
|
108
|
+
// and in the component$() it can be access with useEndpoint()
|
|
109
|
+
response.headers.set('Cache-Control', 'no-cache, no-store, no-fun');
|
|
110
|
+
return {
|
|
111
|
+
productId: params.id,
|
|
112
|
+
price: productPrice,
|
|
113
|
+
description: `Node ${process.versions.node} ${os.platform()} ${os.arch()} ${
|
|
114
|
+
os.cpus()[0].model
|
|
115
|
+
}`,
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Our pretty awesome database of prices
|
|
120
|
+
const PRODUCT_DB: Record<string, string> = {
|
|
121
|
+
hat: '$21.96',
|
|
122
|
+
jacket: '$48.96',
|
|
123
|
+
tshirt: '$18.96',
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
type EndpointData = ProductData | null;
|
|
127
|
+
|
|
128
|
+
interface ProductData {
|
|
129
|
+
productId: string;
|
|
130
|
+
price: string;
|
|
131
|
+
description: string;
|
|
132
|
+
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { component$, Host, Slot } from '@builder.io/qwik';
|
|
2
|
-
|
|
3
|
-
export default component$(() => {
|
|
4
|
-
return (
|
|
5
|
-
<Host>
|
|
6
|
-
<section>
|
|
7
|
-
<Slot />
|
|
8
|
-
</section>
|
|
9
|
-
<aside>
|
|
10
|
-
<p>Account Help</p>
|
|
11
|
-
<ul>
|
|
12
|
-
<li>Forgot password</li>
|
|
13
|
-
</ul>
|
|
14
|
-
</aside>
|
|
15
|
-
</Host>
|
|
16
|
-
);
|
|
17
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { component$, Host } from '@builder.io/qwik';
|
|
2
|
-
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
3
|
-
|
|
4
|
-
export default component$(() => {
|
|
5
|
-
return (
|
|
6
|
-
<Host>
|
|
7
|
-
<h1>Sign In</h1>
|
|
8
|
-
<form action="/api/on-sign-in" method="post">
|
|
9
|
-
<label>
|
|
10
|
-
<span>Username</span>
|
|
11
|
-
<input name="username" type="text" />
|
|
12
|
-
</label>
|
|
13
|
-
<label>
|
|
14
|
-
<span>Password</span>
|
|
15
|
-
<input name="password" type="password" />
|
|
16
|
-
</label>
|
|
17
|
-
<button>Log In</button>
|
|
18
|
-
</form>
|
|
19
|
-
</Host>
|
|
20
|
-
);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
export const head: DocumentHead = {
|
|
24
|
-
title: 'Sign In',
|
|
25
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { component$, Host } from '@builder.io/qwik';
|
|
2
|
-
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
3
|
-
|
|
4
|
-
export default component$(() => {
|
|
5
|
-
return (
|
|
6
|
-
<Host>
|
|
7
|
-
<h1>Sign Up</h1>
|
|
8
|
-
<form>
|
|
9
|
-
<label>
|
|
10
|
-
<span>Username</span>
|
|
11
|
-
<input type="text" />
|
|
12
|
-
</label>
|
|
13
|
-
<label>
|
|
14
|
-
<span>Password</span>
|
|
15
|
-
<input type="password" />
|
|
16
|
-
</label>
|
|
17
|
-
<label>
|
|
18
|
-
<span>Re-entry Password</span>
|
|
19
|
-
<input type="password" />
|
|
20
|
-
</label>
|
|
21
|
-
<button>Create Account</button>
|
|
22
|
-
</form>
|
|
23
|
-
</Host>
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
export const head: DocumentHead = {
|
|
28
|
-
title: 'Sign Up',
|
|
29
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { component$, Host, Slot, useStyles$ } from '@builder.io/qwik';
|
|
2
|
-
import type { DocumentHead } from '@builder.io/qwik-city';
|
|
3
|
-
import { Menu } from '../../../components/menu/menu';
|
|
4
|
-
import styles from './docs.css?inline';
|
|
5
|
-
|
|
6
|
-
export default component$(() => {
|
|
7
|
-
useStyles$(styles);
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<Host class="docs">
|
|
11
|
-
<Menu />
|
|
12
|
-
<section class="docs-content">
|
|
13
|
-
<Slot />
|
|
14
|
-
</section>
|
|
15
|
-
</Host>
|
|
16
|
-
);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export const head: DocumentHead = ({ head }) => {
|
|
20
|
-
return {
|
|
21
|
-
title: `Docs: ${head.title}`,
|
|
22
|
-
};
|
|
23
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Welcome
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Counter } from '~/components/counter/counter';
|
|
6
|
-
|
|
7
|
-
# Welcome
|
|
8
|
-
|
|
9
|
-
Welcome to the fabulous Qwik City. QwikCity is our official kit to build amazing sites:
|
|
10
|
-
|
|
11
|
-
- 🐎 Powered by Qwik. Zero hydration and instant interactivity.
|
|
12
|
-
- 🗃 File based routing (like Nextjs)
|
|
13
|
-
- 🌏 Deploy easily to the edge: Netlify, Cloudflare, Vercel, Deno...
|
|
14
|
-
- 📖 Author content directly in Markdown or MDX. MDX brings the best of markdown and JSX, allowing you to render Qwik components directly in markdown, like this one:
|
|
15
|
-
|
|
16
|
-
<Counter />
|
|
17
|
-
|
|
18
|
-
## Next steps
|
|
19
|
-
|
|
20
|
-
Open your editor and check out the following:
|
|
21
|
-
|
|
22
|
-
**The `src/routes` folder**
|
|
23
|
-
|
|
24
|
-
This is where the main content lives. Adding folders and / or files (`.md`, `.mdx`, or `.tsx`) will automatically create new URLs. For example, code saved at `routes/dashboard/settings/index.tsx` will be accessible via the URL path `/dashboard/settings`.
|
|
25
|
-
|
|
26
|
-
**The `src/routes/_layout` files and folders**
|
|
27
|
-
|
|
28
|
-
These bring form to your content. Since different pages may need to be rendered by different layouts, QwikCity provides the ability to scope layouts to specific routes, while still allowing for easy reuse across different content. For any page without its own layout defined, the `src/routes/_layout.tsx` is used by default.
|
|
29
|
-
|
|
30
|
-
**The `src/components` folder**
|
|
31
|
-
|
|
32
|
-
QwikCity is still a normal Qwik app. Any custom component, design systems, or functionality should live here. Notice the `header`, `footer` and `content-nav` components. They are used by the `default` layout!
|