create-qwik 0.0.33 → 0.0.34-dev20220701233003
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/create-qwik +45 -45
- package/index.js +9 -9
- package/package.json +2 -2
- package/starters/apps/base/gitignore +4 -0
- package/starters/apps/base/package.json +8 -8
- package/starters/apps/base/src/entry.dev.tsx +1 -1
- package/starters/apps/{library → base}/src/entry.ssr.tsx +1 -1
- package/starters/apps/base/src/root.tsx +1 -1
- package/starters/apps/blank/package.json +18 -0
- package/starters/apps/{starter → blank}/src/components/app/app.tsx +0 -0
- package/starters/apps/{starter → blank}/src/components/logo/logo.tsx +0 -0
- package/starters/apps/blank/src/entry.express.tsx +52 -0
- package/starters/apps/{todo → blank}/src/entry.ssr.tsx +1 -1
- package/starters/apps/{starter-partytown → blank}/src/global.css +0 -0
- package/starters/apps/{starter → blank}/src/root.tsx +1 -1
- package/starters/apps/library/package.json +0 -1
- package/starters/apps/library/src/root.tsx +1 -1
- package/starters/apps/qwik-city/package.json +4 -2
- package/starters/apps/qwik-city/src/components/footer/footer.css +21 -4
- package/starters/apps/qwik-city/src/components/footer/footer.tsx +23 -9
- package/starters/apps/qwik-city/src/components/head/analytics.tsx +13 -0
- package/starters/apps/qwik-city/src/components/head/head.tsx +37 -0
- package/starters/apps/qwik-city/src/components/head/social.tsx +10 -0
- package/starters/apps/qwik-city/src/components/header/header.css +34 -2
- package/starters/apps/qwik-city/src/components/header/header.tsx +41 -13
- package/starters/apps/qwik-city/src/components/menu/menu.css +3 -0
- package/starters/apps/qwik-city/src/components/menu/menu.tsx +39 -0
- package/starters/apps/qwik-city/src/root.tsx +8 -22
- package/starters/apps/qwik-city/src/routes/__auth/_layout.tsx +17 -0
- package/starters/apps/qwik-city/src/routes/__auth/sign-in.tsx +29 -0
- package/starters/apps/qwik-city/src/routes/__auth/sign-up.tsx +33 -0
- package/starters/apps/qwik-city/src/routes/_layout.tsx +15 -0
- package/starters/apps/qwik-city/src/routes/about-us.tsx +21 -0
- package/starters/apps/qwik-city/src/routes/api/[org]/[user].json/index.ts +42 -0
- package/starters/apps/qwik-city/src/routes/api/_layout-foo/api.css +14 -0
- package/starters/apps/qwik-city/src/routes/api/_layout-foo/index.tsx +40 -0
- package/starters/apps/qwik-city/src/routes/api/data.json.ts +21 -0
- package/starters/apps/qwik-city/src/routes/api/index@foo.tsx +36 -0
- package/starters/apps/qwik-city/src/routes/blog/[...slug].tsx +13 -0
- package/starters/apps/qwik-city/src/routes/blog/_layout/index.tsx +21 -0
- package/starters/apps/qwik-city/src/routes/blog/index.md +7 -0
- package/starters/apps/qwik-city/src/routes/dashboard/_layout-dashboard.tsx +18 -0
- package/starters/apps/qwik-city/src/routes/dashboard/index.tsx +9 -0
- package/starters/apps/qwik-city/src/routes/dashboard/profile@dashboard.tsx +10 -0
- package/starters/apps/qwik-city/src/routes/dashboard/settings/index@dashboard.tsx +10 -0
- package/starters/apps/qwik-city/src/routes/docs/[category]/[id]/index.tsx +15 -0
- package/starters/apps/qwik-city/src/routes/docs/_layout/docs.css +9 -0
- package/starters/apps/qwik-city/src/routes/docs/_layout/index.tsx +25 -0
- package/starters/apps/qwik-city/src/routes/docs/_menu.md +9 -0
- package/starters/apps/qwik-city/src/{pages/index.mdx → routes/docs/getting-started.mdx} +1 -1
- package/starters/apps/qwik-city/src/routes/docs/index.tsx +18 -0
- package/starters/apps/qwik-city/src/routes/docs/introduction/index.md +7 -0
- package/starters/apps/qwik-city/src/routes/index.tsx +11 -0
- package/starters/apps/qwik-city/tsconfig.json +24 -0
- package/starters/apps/qwik-city/vite.config.ts +3 -7
- package/starters/features/prettier/package.json +1 -1
- package/starters/features/react/package.json +26 -0
- package/starters/{apps/qwik-city → features/react}/src/entry.ssr.tsx +3 -2
- package/starters/features/react/src/react/app.tsx +14 -0
- package/starters/servers/cloudflare-pages/functions/[[path]].ts +1 -1
- package/starters/servers/cloudflare-pages/src/entry.cloudflare.tsx +2 -2
- package/starters/servers/express/src/entry.express.tsx +5 -38
- package/starters/servers/netlify/package.json +1 -1
- package/starters/apps/qwik-city/src/components/app/app.tsx +0 -13
- package/starters/apps/qwik-city/src/components/page/page.tsx +0 -24
- package/starters/apps/qwik-city/src/components/sidebar/sidebar.css +0 -12
- package/starters/apps/qwik-city/src/components/sidebar/sidebar.tsx +0 -54
- package/starters/apps/qwik-city/src/entry.dev.tsx +0 -13
- package/starters/apps/qwik-city/src/layouts/default/default.css +0 -171
- package/starters/apps/qwik-city/src/layouts/default/default.tsx +0 -24
- package/starters/apps/qwik-city/src/layouts/not-found/not-found.css +0 -0
- package/starters/apps/qwik-city/src/layouts/not-found/not-found.tsx +0 -18
- package/starters/apps/qwik-city/src/pages/INDEX +0 -16
- package/starters/apps/qwik-city/src/pages/blog/progressive.mdx +0 -70
- package/starters/apps/qwik-city/src/pages/blog/reactivity.mdx +0 -155
- package/starters/apps/qwik-city/src/pages/blog/resumable.mdx +0 -107
- package/starters/apps/starter/package.json +0 -10
- package/starters/apps/starter/src/entry.ssr.tsx +0 -15
- package/starters/apps/starter/src/global.css +0 -3
- package/starters/apps/starter-partytown/package.json +0 -13
- package/starters/apps/starter-partytown/src/components/app/app.tsx +0 -89
- package/starters/apps/starter-partytown/src/entry.ssr.tsx +0 -16
- package/starters/apps/starter-partytown/src/root.tsx +0 -36
- package/starters/apps/todo/package.json +0 -7
- package/starters/apps/todo/src/components/app/app.tsx +0 -39
- package/starters/apps/todo/src/components/app/base.css +0 -141
- package/starters/apps/todo/src/components/app/index.css +0 -378
- package/starters/apps/todo/src/components/body/body.tsx +0 -16
- package/starters/apps/todo/src/components/footer/footer.tsx +0 -63
- package/starters/apps/todo/src/components/header/header.tsx +0 -40
- package/starters/apps/todo/src/components/item/item.tsx +0 -76
- package/starters/apps/todo/src/root.tsx +0 -15
- package/starters/apps/todo/src/state/state.ts +0 -29
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Resumable
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Resumable vs. Hydration
|
|
6
|
-
|
|
7
|
-
A key concept of Qwik applications is that they are resumable from server-side-rendered state. The best way to explain resumability is to understand how the current generation of frameworks are replayable (hydration).
|
|
8
|
-
|
|
9
|
-
When an SSR/SSG application boots up on a client, it requires that the framework on the client restore two pieces of information:
|
|
10
|
-
|
|
11
|
-
1. Locate event listeners and install them on the DOM nodes to make the application interactive;
|
|
12
|
-
2. Build up an internal data structure representing the application component tree.
|
|
13
|
-
3. Restore the application state.
|
|
14
|
-
|
|
15
|
-
Collectively, this is known as hydration. All current generations of frameworks require this step to make the application interactive.
|
|
16
|
-
|
|
17
|
-
[Hydration is expensive](https://www.builder.io/blog/hydration-is-pure-overhead) for two reasons:
|
|
18
|
-
|
|
19
|
-
1. The frameworks have to download all of the component code associated with the current page.
|
|
20
|
-
2. The frameworks have to execute the templates associated with the components on the page to rebuild the listener location and the internal component tree.
|
|
21
|
-
|
|
22
|
-

|
|
23
|
-
|
|
24
|
-
Qwik is different because it does not require hydration to resume an application on the client. Not requiring hydration is what makes the Qwik application startup instantaneous.
|
|
25
|
-
|
|
26
|
-
All frameworks hydration **replay** all the application logic in the client, instead Qwik pauses execution in the server, and resumes execution in the client,
|
|
27
|
-
|
|
28
|
-
# Introducing Resumability
|
|
29
|
-
|
|
30
|
-
Resumability is about pausing execution in the server, and resuming execution in the client without having to replay and download all of the application logic.
|
|
31
|
-
|
|
32
|
-
A good mental model is that Qwik applications at any point in their lifecycle can be serialized and moved to a different VM instance. (Server to browser). There, the application simply resumes where the serialization stopped. No hydration is required. This is why we say that Qwik applications don't hydrate; they resume.
|
|
33
|
-
|
|
34
|
-
In order to achieve this, qwik needs to solve the 3 problems (listeners, component tree, application state) in a way that is compatible with a no-code startup.
|
|
35
|
-
|
|
36
|
-
## Listeners
|
|
37
|
-
|
|
38
|
-
DOM without event listeners is just a static page; it is not an application. Today's standard for all sites is quite a high level of interactivity, so even the most static-looking sites are full of event listeners. These include menus, hovers, expanding details, or even full-on interactive apps.
|
|
39
|
-
|
|
40
|
-
Existing frameworks solve the event listener by downloading the components and executing their templates to collect event listeners that are then attached to the DOM. The current approach has these issues:
|
|
41
|
-
|
|
42
|
-
1. Requires the template code to be eagerly downloaded;
|
|
43
|
-
2. Requires template code to be eagerly executed;
|
|
44
|
-
3. Requires the event handler code to be downloaded eagerly (to be attached.)
|
|
45
|
-
|
|
46
|
-
The above approach does not scale. As the application becomes more complicated, the amount of code needed to download eagerly and execute grows proportionally with the size of the application. This negatively impacts the application startup performance and hence the user experience.
|
|
47
|
-
|
|
48
|
-
Qwik solves the above issue by serializing the event listens into DOM like so:
|
|
49
|
-
|
|
50
|
-
```html
|
|
51
|
-
<button onClickQrl="./chunk.js#handler_symbol">click me</button>
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Qwik still needs to collect the listener information, but this step is done as part of the SSR/SSG. The results of SSR/SSG are then serialized into HTML so that the browser does not need to do anything to resume the execution. Notice that the `onClickQrl` attribute contains all of the information to resume the application without doing anything eagerly.
|
|
55
|
-
|
|
56
|
-
1. Qwikloader sets up a single global listener instead of many individual listeners per DOM element. This step can be done with no application code present.
|
|
57
|
-
2. The HTML contains a URL to the chunk and symbol name. The attribute tells Qwikloader which code chunk to download and which symbol to retrieve from the chunk.
|
|
58
|
-
3. Finally, to make all of the above possible, Qwik's event processing implementation understands asynchronicity which allows insertion of asynchronous lazy loading.
|
|
59
|
-
|
|
60
|
-
## Component Trees
|
|
61
|
-
|
|
62
|
-
Frameworks work with component trees. To that end, frameworks need a complete understanding of the component trees to know which components need to be rerendered and when. If you look into the existing framework SSR/SSG output, the component boundary information has been destroyed. There is no way of knowing where component boundaries are by looking at the resulting HTML. To recreate this information, frameworks re-execute the component templates and memoize the component boundary location. Re-execution is what hydration is. Hydration is expensive as it requires both the download of component templates and their execution.
|
|
63
|
-
|
|
64
|
-
Qwik collects component boundary information as part of the SSR/SSG and then serializes that information into HTML. The result is that Qwik can:
|
|
65
|
-
|
|
66
|
-
1. Rebuild the component hierarchy information without the component code actually being present. The component code can remain lazy.
|
|
67
|
-
2. Qwik can do this lazily only for the components which need to be rerendered rather than all upfront.
|
|
68
|
-
3. Qwik collects relationship information between stores and components. This creates a subscription model that informs Qwik which components need to be re-rendered as a result of state change. The subscription information also gets serialized into HTML.
|
|
69
|
-
|
|
70
|
-
## Application State
|
|
71
|
-
|
|
72
|
-
Existing frameworks usually have a way of serializing the application state into HTML so that the state can be restored as part of hydration. In this way, they are very similar to Qwik. However, Qwik has state management more tightly integrated into the lifecycle of the components. In practice, this means that component can be delayed loaded independently from the state of the component. This is not easily achievable in existing frameworks because component props are usually created by the parent component. This creates a chain reaction. In order to restore component X, its parents need to be restored as well. Qwik allows any component to be resumed without the parent component code being present.
|
|
73
|
-
|
|
74
|
-
### Serialization
|
|
75
|
-
|
|
76
|
-
The simplest way to think about serialization is through `JSON.stringify`. However, JSON has several limitations. Qwik can overcome some limitations, but some can't be overcome, and they place limitations on what the developer can do. Understanding these limitations is important when building Qwik applications.
|
|
77
|
-
|
|
78
|
-
Limitations of JSON which Qwik solves:
|
|
79
|
-
|
|
80
|
-
- JSON produces DAG. DAG stands for directed acyclic graph, which means that the object which is being serialized can't have circular references. This is a big limitation because the application state is often circular. Qwik ensures that when the graph of objects gets serialized, the circular references get properly saved and then restored.
|
|
81
|
-
- JSON can't serialize some object types. For example, DOM references, Dates, etc... Qwik serialization format ensures that such objects can correctly be serialized and restored. Here is a list of types that can be serialized with Qwik:
|
|
82
|
-
- DOM references
|
|
83
|
-
- Dates (not yet implemented)
|
|
84
|
-
- Function closures (if wrapped in QRL).
|
|
85
|
-
|
|
86
|
-
Limitations of JSON that Qwik does not solve:
|
|
87
|
-
|
|
88
|
-
- Serialization of classes (`instanceof` and prototype)
|
|
89
|
-
- Serialization of `Promise`s, Streams, etc...
|
|
90
|
-
|
|
91
|
-
## Writing applications with serializability in mind
|
|
92
|
-
|
|
93
|
-
The resumability property of the framework must extend to resumability of the application as well. This means that the framework must provide mechanisms for the developer to express Components and Entities of the applications in a way which can be serialized and then resumed (without re-bootstrapping). This necessitates that applications are written with resumability constraints in mind. It is simply not possible for developers to continue to write applications in a heap-centric way and expect that a better framework can somehow make up for this sub-optimal approach.
|
|
94
|
-
|
|
95
|
-
Developers must write their applications in a DOM-centric way. This will require a change of behavior and retooling of web-developers skills. Frameworks need to provide guidance and APIs to make it easy for developers to write the applications in this way.
|
|
96
|
-
|
|
97
|
-
## Other benefits of resumability
|
|
98
|
-
|
|
99
|
-
The most obvious benefit of using resumability is for server-side-rendering. However, there are secondary benefits:
|
|
100
|
-
|
|
101
|
-
- Serializing existing PWA apps so that users don't loose context when they return to the application
|
|
102
|
-
- Improved rendering performance because only changed components need to be re-rendered
|
|
103
|
-
- Fine-grained-lazy loading
|
|
104
|
-
- Decreased memory pressure, especially on mobile devices
|
|
105
|
-
- Progressive interactivity of existing static websites
|
|
106
|
-
|
|
107
|
-
Reactivity is a key component of Qwik. Reactivity allows Qwik to track which components are subscribed to which state. This information enables Qwik to invalidate only the relevant component on state change, which minimizes the number of components that need to be rerendered. Without reactivity, a state change would require rerendering from the root component, which would force the whole component tree to be eagerly downloaded.
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { renderToString, RenderOptions } from '@builder.io/qwik/server';
|
|
2
|
-
import { manifest } from '@qwik-client-manifest';
|
|
3
|
-
import { Root } from './root';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Server-Side Render method to be called by a server.
|
|
7
|
-
*/
|
|
8
|
-
export function render(opts?: RenderOptions) {
|
|
9
|
-
// Render the Root component to a string
|
|
10
|
-
// Pass in the manifest that was generated from the client build
|
|
11
|
-
return renderToString(<Root />, {
|
|
12
|
-
manifest,
|
|
13
|
-
...opts,
|
|
14
|
-
});
|
|
15
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { component$, useStore } from '@builder.io/qwik';
|
|
2
|
-
|
|
3
|
-
export const App = component$(() => {
|
|
4
|
-
const state = useStore({ name: 'World', running: true });
|
|
5
|
-
|
|
6
|
-
return (
|
|
7
|
-
<div id="my-app" onDocumentExpensiveComputationDone$={() => (state.running = false)}>
|
|
8
|
-
<p style={{ 'text-align': 'center' }}>
|
|
9
|
-
<a href="https://github.com/builderio/qwik">
|
|
10
|
-
<img
|
|
11
|
-
alt="Qwik Logo"
|
|
12
|
-
width={400}
|
|
13
|
-
src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F667ab6c2283d4c4d878fb9083aacc10f"
|
|
14
|
-
/>
|
|
15
|
-
</a>
|
|
16
|
-
</p>
|
|
17
|
-
<p class="congrats">
|
|
18
|
-
Congratulations <a href="https://github.com/builderio/qwik">Qwik</a> with{' '}
|
|
19
|
-
<a href="https://partytown.builder.io/">Partytown</a> is working!
|
|
20
|
-
</p>
|
|
21
|
-
|
|
22
|
-
<p>
|
|
23
|
-
Expensive script running in <a href="https://partytown.builder.io/">Partytown</a> is{' '}
|
|
24
|
-
{state.running ? (
|
|
25
|
-
<span style={{ 'background-color': 'red', color: 'white', padding: '.1em' }}>
|
|
26
|
-
running
|
|
27
|
-
</span>
|
|
28
|
-
) : (
|
|
29
|
-
<span style={{ 'background-color': 'green', color: 'white', padding: '.1em' }}>
|
|
30
|
-
finished
|
|
31
|
-
</span>
|
|
32
|
-
)}
|
|
33
|
-
.
|
|
34
|
-
</p>
|
|
35
|
-
|
|
36
|
-
<p>Next steps:</p>
|
|
37
|
-
<ol>
|
|
38
|
-
<li>
|
|
39
|
-
Open dev-tools network tab and notice that no JavaScript was downloaded by the main thread
|
|
40
|
-
to render this page. (<code>partytown.js</code> is used to execute things of main thread
|
|
41
|
-
and not for rendering the application.)
|
|
42
|
-
</li>
|
|
43
|
-
<li>
|
|
44
|
-
Partytown executes <code><script></code> tag that contains a simulation of expensive
|
|
45
|
-
script. The expensive script simplation keeps the web-worker thread busy for 2.5 seconds,
|
|
46
|
-
leaving main-thread free for user interactions. (Without Partytown the script would block
|
|
47
|
-
the main thread resulting in poor user experience.)
|
|
48
|
-
</li>
|
|
49
|
-
<li>
|
|
50
|
-
Once the expensive operation is finished it dispatches custom event (
|
|
51
|
-
<code>expensiveComputationDone</code>) that this component listens on. It is only at that
|
|
52
|
-
time that Qwik lazy-loads the component render function and updates the UI. (See network
|
|
53
|
-
tab.)
|
|
54
|
-
</li>
|
|
55
|
-
<li>
|
|
56
|
-
Try interacting with this component by changing{' '}
|
|
57
|
-
<input
|
|
58
|
-
value={state.name}
|
|
59
|
-
onKeyUp$={(event) => {
|
|
60
|
-
const input = event.target as HTMLInputElement;
|
|
61
|
-
state.name = input.value;
|
|
62
|
-
}}
|
|
63
|
-
></input>
|
|
64
|
-
.
|
|
65
|
-
</li>
|
|
66
|
-
<li>
|
|
67
|
-
Observe that the binding changes: <code>Hello {state.name}!</code>
|
|
68
|
-
</li>
|
|
69
|
-
<li>
|
|
70
|
-
Notice that Qwik automatically lazily-loaded and resumed the component upon interaction
|
|
71
|
-
without the developer having to code that behavior. (Lazy hydration is what gives even
|
|
72
|
-
large apps instant on behavior.)
|
|
73
|
-
</li>
|
|
74
|
-
<li>
|
|
75
|
-
Read the docs <a href="https://github.com/builderio/qwik">here</a>.
|
|
76
|
-
</li>
|
|
77
|
-
<li>Replace the content of this component with your code.</li>
|
|
78
|
-
<li>Build amazing web-sites with unbeatable startup performance.</li>
|
|
79
|
-
</ol>
|
|
80
|
-
<hr />
|
|
81
|
-
<p style={{ 'text-align': 'center' }}>
|
|
82
|
-
Made with ❤️ by{' '}
|
|
83
|
-
<a target="_blank" href="https://www.builder.io/">
|
|
84
|
-
Builder.io
|
|
85
|
-
</a>
|
|
86
|
-
</p>
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { renderToString, RenderOptions } from '@builder.io/qwik/server';
|
|
2
|
-
import { manifest } from '@qwik-client-manifest';
|
|
3
|
-
import { Root } from './root';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Qwik server-side render function.
|
|
7
|
-
*/
|
|
8
|
-
export function render(opts: RenderOptions) {
|
|
9
|
-
return renderToString(<Root />, {
|
|
10
|
-
manifest,
|
|
11
|
-
qwikLoader: {
|
|
12
|
-
events: ['click', 'keyup', 'expensiveComputationDone'],
|
|
13
|
-
},
|
|
14
|
-
...opts,
|
|
15
|
-
});
|
|
16
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { App } from './components/app/app';
|
|
2
|
-
import { partytownSnippet } from '@builder.io/partytown/integration';
|
|
3
|
-
|
|
4
|
-
import './global.css';
|
|
5
|
-
|
|
6
|
-
export const Root = () => {
|
|
7
|
-
return (
|
|
8
|
-
<html>
|
|
9
|
-
<head>
|
|
10
|
-
<meta charSet="utf-8" />
|
|
11
|
-
<title>Qwik + Partytown Blank App</title>
|
|
12
|
-
<script children={partytownSnippet({ debug: true })} />
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<App />
|
|
16
|
-
<script type="text/partytown">
|
|
17
|
-
({partyTownExampleWhichBlocksMainThreadForOneSecond.toString()})()
|
|
18
|
-
</script>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
21
|
-
);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
function partyTownExampleWhichBlocksMainThreadForOneSecond() {
|
|
25
|
-
// Block execution for 1 second.
|
|
26
|
-
const start = new Date().getTime();
|
|
27
|
-
// eslint-disable-next-line no-console
|
|
28
|
-
console.log('Expensive computation started at:', start);
|
|
29
|
-
let end = 0;
|
|
30
|
-
while (end < start + 2500) {
|
|
31
|
-
end = new Date().getTime();
|
|
32
|
-
}
|
|
33
|
-
// eslint-disable-next-line no-console
|
|
34
|
-
console.log('Expensive computation ended at:', end);
|
|
35
|
-
document.dispatchEvent(new Event('expensiveComputationDone', { bubbles: true }));
|
|
36
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { component$, useStyles$, useStore, useContextProvider } from '@builder.io/qwik';
|
|
2
|
-
import { Footer } from '../footer/footer';
|
|
3
|
-
import { Header } from '../header/header';
|
|
4
|
-
import { Body } from '../body/body';
|
|
5
|
-
import { TODOS, Todos } from '../../state/state';
|
|
6
|
-
import styles from './index.css?inline';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Overall application component.
|
|
10
|
-
*
|
|
11
|
-
* This component is static (meaning it will never change). Because of this
|
|
12
|
-
* Qwik knows that it should never need to be rerendered, and its code will never
|
|
13
|
-
* download to the client.
|
|
14
|
-
*/
|
|
15
|
-
export const App = component$(() => {
|
|
16
|
-
useStyles$(styles);
|
|
17
|
-
|
|
18
|
-
const todos = useStore<Todos>(
|
|
19
|
-
{
|
|
20
|
-
filter: 'all',
|
|
21
|
-
items: [
|
|
22
|
-
{ completed: false, title: 'Read Qwik docs', id: '0' },
|
|
23
|
-
{ completed: false, title: 'Build HelloWorld', id: '1' },
|
|
24
|
-
{ completed: false, title: 'Profit', id: '2' },
|
|
25
|
-
],
|
|
26
|
-
nextItemId: 3,
|
|
27
|
-
},
|
|
28
|
-
{ recursive: true }
|
|
29
|
-
);
|
|
30
|
-
useContextProvider(TODOS, todos);
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<section class="todoapp">
|
|
34
|
-
<Header />
|
|
35
|
-
<Body />
|
|
36
|
-
<Footer />
|
|
37
|
-
</section>
|
|
38
|
-
);
|
|
39
|
-
});
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
hr {
|
|
2
|
-
margin: 20px 0;
|
|
3
|
-
border: 0;
|
|
4
|
-
border-top: 1px dashed #c5c5c5;
|
|
5
|
-
border-bottom: 1px dashed #f7f7f7;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.learn a {
|
|
9
|
-
font-weight: normal;
|
|
10
|
-
text-decoration: none;
|
|
11
|
-
color: #b83f45;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.learn a:hover {
|
|
15
|
-
text-decoration: underline;
|
|
16
|
-
color: #787e7e;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.learn h3,
|
|
20
|
-
.learn h4,
|
|
21
|
-
.learn h5 {
|
|
22
|
-
margin: 10px 0;
|
|
23
|
-
font-weight: 500;
|
|
24
|
-
line-height: 1.2;
|
|
25
|
-
color: #000;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.learn h3 {
|
|
29
|
-
font-size: 24px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.learn h4 {
|
|
33
|
-
font-size: 18px;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.learn h5 {
|
|
37
|
-
margin-bottom: 0;
|
|
38
|
-
font-size: 14px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.learn ul {
|
|
42
|
-
padding: 0;
|
|
43
|
-
margin: 0 0 30px 25px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.learn li {
|
|
47
|
-
line-height: 20px;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.learn p {
|
|
51
|
-
font-size: 15px;
|
|
52
|
-
font-weight: 300;
|
|
53
|
-
line-height: 1.3;
|
|
54
|
-
margin-top: 0;
|
|
55
|
-
margin-bottom: 0;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#issue-count {
|
|
59
|
-
display: none;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.quote {
|
|
63
|
-
border: none;
|
|
64
|
-
margin: 20px 0 60px 0;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.quote p {
|
|
68
|
-
font-style: italic;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.quote p:before {
|
|
72
|
-
content: '“';
|
|
73
|
-
font-size: 50px;
|
|
74
|
-
opacity: 0.15;
|
|
75
|
-
position: absolute;
|
|
76
|
-
top: -20px;
|
|
77
|
-
left: 3px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.quote p:after {
|
|
81
|
-
content: '”';
|
|
82
|
-
font-size: 50px;
|
|
83
|
-
opacity: 0.15;
|
|
84
|
-
position: absolute;
|
|
85
|
-
bottom: -42px;
|
|
86
|
-
right: 3px;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.quote footer {
|
|
90
|
-
position: absolute;
|
|
91
|
-
bottom: -40px;
|
|
92
|
-
right: 0;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.quote footer img {
|
|
96
|
-
border-radius: 3px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.quote footer a {
|
|
100
|
-
margin-left: 5px;
|
|
101
|
-
vertical-align: middle;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.speech-bubble {
|
|
105
|
-
position: relative;
|
|
106
|
-
padding: 10px;
|
|
107
|
-
background: rgba(0, 0, 0, 0.04);
|
|
108
|
-
border-radius: 5px;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.speech-bubble:after {
|
|
112
|
-
content: '';
|
|
113
|
-
position: absolute;
|
|
114
|
-
top: 100%;
|
|
115
|
-
right: 30px;
|
|
116
|
-
border: 13px solid transparent;
|
|
117
|
-
border-top-color: rgba(0, 0, 0, 0.04);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.learn-bar > .learn {
|
|
121
|
-
position: absolute;
|
|
122
|
-
width: 272px;
|
|
123
|
-
top: 8px;
|
|
124
|
-
left: -300px;
|
|
125
|
-
padding: 10px;
|
|
126
|
-
border-radius: 5px;
|
|
127
|
-
background-color: rgba(255, 255, 255, 0.6);
|
|
128
|
-
transition-property: left;
|
|
129
|
-
transition-duration: 500ms;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
@media (min-width: 899px) {
|
|
133
|
-
.learn-bar {
|
|
134
|
-
width: auto;
|
|
135
|
-
padding-left: 300px;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.learn-bar > .learn {
|
|
139
|
-
left: 8px;
|
|
140
|
-
}
|
|
141
|
-
}
|