create-qwik 0.0.1 → 0.0.5
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/README.md +23 -6
- package/index.js +106 -1
- package/package.json +17 -25
- package/starters/apps/starter/README.md +3 -0
- package/starters/apps/starter/package.json +25 -0
- package/starters/apps/starter/rollup.config.js +30 -0
- package/starters/apps/starter/src/index.server.qwik.tsx +31 -0
- package/starters/apps/starter/src/my-app.qwik.tsx +63 -0
- package/starters/apps/starter/tsconfig.json +16 -0
- package/starters/apps/starter-builder/README.md +3 -0
- package/starters/apps/starter-builder/package.json +25 -0
- package/starters/apps/starter-builder/rollup.config.js +30 -0
- package/starters/apps/starter-builder/src/index.server.qwik.tsx +46 -0
- package/starters/apps/starter-builder/src/my-app.qwik.tsx +34 -0
- package/starters/apps/starter-builder/tsconfig.json +16 -0
- package/starters/apps/starter-partytown/README.md +3 -0
- package/starters/apps/starter-partytown/package.json +28 -0
- package/starters/apps/starter-partytown/rollup.config.js +30 -0
- package/starters/apps/starter-partytown/src/index.server.qwik.tsx +49 -0
- package/starters/apps/starter-partytown/src/my-app.qwik.tsx +103 -0
- package/starters/apps/starter-partytown/tsconfig.json +16 -0
- package/starters/apps/todo/README.md +3 -0
- package/starters/apps/todo/package.json +25 -0
- package/starters/apps/todo/public/base.css +141 -0
- package/starters/apps/todo/public/index.css +376 -0
- package/starters/apps/todo/rollup.config.js +30 -0
- package/starters/apps/todo/src/components.qwik.tsx +225 -0
- package/starters/apps/todo/src/index.server.qwik.tsx +43 -0
- package/starters/apps/todo/src/state.qwik.ts +64 -0
- package/starters/apps/todo/tsconfig.json +16 -0
- package/starters/servers/express/package.json +10 -0
- package/starters/servers/express/server/index.js +43 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
2
|
+
import { qwikRollup } from '@builder.io/qwik/optimizer';
|
|
3
|
+
import typescript from '@rollup/plugin-typescript';
|
|
4
|
+
|
|
5
|
+
export default async function () {
|
|
6
|
+
return {
|
|
7
|
+
input: [
|
|
8
|
+
'src/index.server.qwik.tsx',
|
|
9
|
+
'src/my-app.qwik.tsx'
|
|
10
|
+
],
|
|
11
|
+
plugins: [
|
|
12
|
+
nodeResolve(),
|
|
13
|
+
qwikRollup({
|
|
14
|
+
symbolsPath: 'q-symbols.json',
|
|
15
|
+
}),
|
|
16
|
+
typescript(),
|
|
17
|
+
],
|
|
18
|
+
output: [
|
|
19
|
+
{
|
|
20
|
+
chunkFileNames: 'q-[hash].js',
|
|
21
|
+
dir: 'public/build',
|
|
22
|
+
format: 'es',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
dir: 'server/build',
|
|
26
|
+
format: 'cjs',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Builder.io, Inc. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://github.com/BuilderIO/qwik/blob/main/LICENSE
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { h } from '@builder.io/qwik';
|
|
10
|
+
import { renderToString, RenderToStringOptions, QwikLoader } from '@builder.io/qwik/server';
|
|
11
|
+
import { Footer, Header } from './my-app.qwik';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Entry point for server-side pre-rendering.
|
|
15
|
+
*
|
|
16
|
+
* @returns a promise when all of the rendering is completed.
|
|
17
|
+
*/
|
|
18
|
+
export default function serverRender(opts: RenderToStringOptions) {
|
|
19
|
+
return renderToString(
|
|
20
|
+
<html>
|
|
21
|
+
<head>
|
|
22
|
+
<title>Qwik Blank App</title>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<Header />
|
|
26
|
+
<div id="my-content"></div>
|
|
27
|
+
<Footer />
|
|
28
|
+
|
|
29
|
+
<script>({fetchQwikBuilderContent.toString()})();</script>
|
|
30
|
+
<QwikLoader debug={opts.debug} />
|
|
31
|
+
</body>
|
|
32
|
+
</html>,
|
|
33
|
+
opts
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const fetchQwikBuilderContent = async () => {
|
|
38
|
+
const qwikUrl = new URL('https://qa.builder.io/api/v1/qwik/page');
|
|
39
|
+
// Demo API key for demonstration only. Please replace with your key
|
|
40
|
+
qwikUrl.searchParams.set('apiKey', '5b8073f890b043be81574f96cfd1250b');
|
|
41
|
+
qwikUrl.searchParams.set('userAttributes.urlPath', location.pathname);
|
|
42
|
+
|
|
43
|
+
const response = await fetch(String(qwikUrl));
|
|
44
|
+
const { html } = await response.json();
|
|
45
|
+
document.querySelector('#my-content')!.innerHTML = html;
|
|
46
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { h, Fragment } from '@builder.io/qwik';
|
|
2
|
+
import { qComponent, qHook } from '@builder.io/qwik';
|
|
3
|
+
|
|
4
|
+
export const Header = qComponent<{}, { name: string }>({
|
|
5
|
+
onRender: qHook(() => {
|
|
6
|
+
return (
|
|
7
|
+
<p style={{ 'text-align': 'center' }}>
|
|
8
|
+
<a href="https://github.com/builderio/qwik">
|
|
9
|
+
<img
|
|
10
|
+
alt="Qwik Logo"
|
|
11
|
+
width={400}
|
|
12
|
+
src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F667ab6c2283d4c4d878fb9083aacc10f"
|
|
13
|
+
/>
|
|
14
|
+
</a>
|
|
15
|
+
</p>
|
|
16
|
+
);
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const Footer = qComponent<{}, { name: string }>({
|
|
21
|
+
onRender: qHook(() => {
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
<hr />
|
|
25
|
+
<p style={{ 'text-align': 'center' }}>
|
|
26
|
+
Made with ❤️ by{' '}
|
|
27
|
+
<a target="_blank" href="https://www.builder.io/">
|
|
28
|
+
Builder.io
|
|
29
|
+
</a>
|
|
30
|
+
</p>
|
|
31
|
+
</>
|
|
32
|
+
);
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"module": "ES2020",
|
|
5
|
+
"lib": ["es2020", "DOM"],
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"jsxFactory": "h",
|
|
8
|
+
"jsxFragmentFactory": "Fragment",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"incremental": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qwik-starter-partytown",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Blank starter app with Partytown",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "npm run clean && rollup -c",
|
|
7
|
+
"clean": "rimraf */build/",
|
|
8
|
+
"start": "npm run clean && concurrently -c blue,green \"rollup -c --configDev --watch\" \"wait-on public/build && npm run serve\""
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@builder.io/qwik": "~0.0.15",
|
|
12
|
+
"@rollup/plugin-node-resolve": "^13.0.6",
|
|
13
|
+
"@rollup/plugin-typescript": "^8.3.0",
|
|
14
|
+
"concurrently": "^6.4.0",
|
|
15
|
+
"rimraf": "^3.0.2",
|
|
16
|
+
"rollup": "^2.59.0",
|
|
17
|
+
"typescript": "^4.5.2",
|
|
18
|
+
"wait-on": "^6.0.0"
|
|
19
|
+
},
|
|
20
|
+
"author": "Builder.io Team",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=14.14.0"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@builder.io/partytown": "^0.0.22"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
2
|
+
import { qwikRollup } from '@builder.io/qwik/optimizer';
|
|
3
|
+
import typescript from '@rollup/plugin-typescript';
|
|
4
|
+
|
|
5
|
+
export default async function () {
|
|
6
|
+
return {
|
|
7
|
+
input: [
|
|
8
|
+
'src/index.server.qwik.tsx',
|
|
9
|
+
'src/my-app.qwik.tsx'
|
|
10
|
+
],
|
|
11
|
+
plugins: [
|
|
12
|
+
nodeResolve(),
|
|
13
|
+
qwikRollup({
|
|
14
|
+
symbolsPath: 'q-symbols.json',
|
|
15
|
+
}),
|
|
16
|
+
typescript(),
|
|
17
|
+
],
|
|
18
|
+
output: [
|
|
19
|
+
{
|
|
20
|
+
chunkFileNames: 'q-[hash].js',
|
|
21
|
+
dir: 'public/build',
|
|
22
|
+
format: 'es',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
dir: 'server/build',
|
|
26
|
+
format: 'cjs',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Builder.io, Inc. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://github.com/BuilderIO/qwik/blob/main/LICENSE
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { h } from '@builder.io/qwik';
|
|
10
|
+
import { renderToString, RenderToStringOptions, QwikLoader } from '@builder.io/qwik/server';
|
|
11
|
+
import { MyApp } from './my-app.qwik';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Entry point for server-side pre-rendering.
|
|
15
|
+
*
|
|
16
|
+
* @returns a promise when all of the rendering is completed.
|
|
17
|
+
*/
|
|
18
|
+
export default function serverRender(opts: RenderToStringOptions) {
|
|
19
|
+
return renderToString(
|
|
20
|
+
<html>
|
|
21
|
+
<head>
|
|
22
|
+
<title>Qwik + Partytown Blank App</title>
|
|
23
|
+
<script defer async src="~partytown/debug/partytown.js"></script>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<MyApp />
|
|
27
|
+
<script type="text/partytown">
|
|
28
|
+
({partyTownExampleWhichBlocksMainThreadForOneSecond.toString()})()
|
|
29
|
+
</script>
|
|
30
|
+
<QwikLoader debug={opts.debug} events={['click', 'keyup', 'expensive-computation-done']} />
|
|
31
|
+
</body>
|
|
32
|
+
</html>,
|
|
33
|
+
opts
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function partyTownExampleWhichBlocksMainThreadForOneSecond() {
|
|
38
|
+
// Block execution for 1 second.
|
|
39
|
+
const start = new Date().getTime();
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
console.log('Expensive computation started at:', start);
|
|
42
|
+
let end = 0;
|
|
43
|
+
while (end < start + 2500) {
|
|
44
|
+
end = new Date().getTime();
|
|
45
|
+
}
|
|
46
|
+
// eslint-disable-next-line no-console
|
|
47
|
+
console.log('Expensive computation ended at:', end);
|
|
48
|
+
document.dispatchEvent(new Event('expensive-computation-done', { bubbles: true }));
|
|
49
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { h, qEvent } from '@builder.io/qwik';
|
|
2
|
+
import { qComponent, qHook, useEvent } from '@builder.io/qwik';
|
|
3
|
+
|
|
4
|
+
export const expensiveComputationDone = qEvent('document:expensiveComputationDone');
|
|
5
|
+
|
|
6
|
+
export const MyApp = qComponent<{}, { name: string; running: boolean }>({
|
|
7
|
+
tagName: 'my-app', // optional
|
|
8
|
+
onMount: qHook(() => ({ name: 'World', running: true })),
|
|
9
|
+
onRender: qHook((props, state) => {
|
|
10
|
+
// eslint-disable-next-line no-console
|
|
11
|
+
console.log('Qwik: MyApp component is rendering...');
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
id="my-app"
|
|
15
|
+
{...expensiveComputationDone(
|
|
16
|
+
qHook<typeof MyApp>((props, state) => (state.running = false))
|
|
17
|
+
)}
|
|
18
|
+
>
|
|
19
|
+
<p style={{ 'text-align': 'center' }}>
|
|
20
|
+
<a href="https://github.com/builderio/qwik">
|
|
21
|
+
<img
|
|
22
|
+
alt="Qwik Logo"
|
|
23
|
+
width={400}
|
|
24
|
+
src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F667ab6c2283d4c4d878fb9083aacc10f"
|
|
25
|
+
/>
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
|
+
<p>
|
|
29
|
+
Congratulations <a href="https://github.com/builderio/qwik">Qwik</a> with{' '}
|
|
30
|
+
<a href="https://github.com/BuilderIO/partytown">Partytown</a> is working!
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
<p>
|
|
34
|
+
Expensive script running in <a href="https://github.com/BuilderIO/partytown">Partytown</a>{' '}
|
|
35
|
+
is{' '}
|
|
36
|
+
{state.running ? (
|
|
37
|
+
<span style={{ 'background-color': 'red', color: 'white', padding: '.1em' }}>
|
|
38
|
+
running
|
|
39
|
+
</span>
|
|
40
|
+
) : (
|
|
41
|
+
<span style={{ 'background-color': 'green', color: 'white', padding: '.1em' }}>
|
|
42
|
+
finished
|
|
43
|
+
</span>
|
|
44
|
+
)}
|
|
45
|
+
.
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
<p>Next steps:</p>
|
|
49
|
+
<ol>
|
|
50
|
+
<li>
|
|
51
|
+
Open dev-tools network tab and notice that no JavaScript was downloaded by the main
|
|
52
|
+
thread to render this page. (<code>partytown.js</code> is used to execute things of main
|
|
53
|
+
thread and not for rendering the application.)
|
|
54
|
+
</li>
|
|
55
|
+
<li>
|
|
56
|
+
Partytown executes <code><script></code> tag that contains a simulation of
|
|
57
|
+
expensive script. The expensive script simplation keeps the web-worker thread busy for
|
|
58
|
+
2.5 seconds, leaving main-thread free for user interactions. (Without Partytown the
|
|
59
|
+
script would block the main thread resulting in poor user experience.)
|
|
60
|
+
</li>
|
|
61
|
+
<li>
|
|
62
|
+
Once the expensive operation is finished it dispatches custom event (
|
|
63
|
+
<code>expensivecomputationdone</code>) that this component listens on. It is only at
|
|
64
|
+
that time that Qwik lazy-loads the component render function and updates the UI. (See
|
|
65
|
+
network tab.)
|
|
66
|
+
</li>
|
|
67
|
+
<li>
|
|
68
|
+
Try interacting with this component by changing{' '}
|
|
69
|
+
<input
|
|
70
|
+
value={state.name}
|
|
71
|
+
on:keyup={qHook<typeof MyApp>((props, state) => {
|
|
72
|
+
const event = useEvent<KeyboardEvent>();
|
|
73
|
+
const input = event.target as HTMLInputElement;
|
|
74
|
+
state.name = input.value;
|
|
75
|
+
})}
|
|
76
|
+
></input>
|
|
77
|
+
.
|
|
78
|
+
</li>
|
|
79
|
+
<li>
|
|
80
|
+
Observe that the binding changes: <code>Hello {state.name}!</code>
|
|
81
|
+
</li>
|
|
82
|
+
<li>
|
|
83
|
+
Notice that Qwik automatically lazily-loaded and hydrated the component upon interaction
|
|
84
|
+
without the developer having to code that behavior. (Lazy hydration is what gives even
|
|
85
|
+
large apps instant on behavior.)
|
|
86
|
+
</li>
|
|
87
|
+
<li>
|
|
88
|
+
Read the docs <a href="https://github.com/builderio/qwik">here</a>.
|
|
89
|
+
</li>
|
|
90
|
+
<li>Replace the content of this component with your code.</li>
|
|
91
|
+
<li>Build amazing web-sites with unbeatable startup performance.</li>
|
|
92
|
+
</ol>
|
|
93
|
+
<hr />
|
|
94
|
+
<p style={{ 'text-align': 'center' }}>
|
|
95
|
+
Made with ❤️ by{' '}
|
|
96
|
+
<a target="_blank" href="https://www.builder.io/">
|
|
97
|
+
Builder.io
|
|
98
|
+
</a>
|
|
99
|
+
</p>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"module": "ES2020",
|
|
5
|
+
"lib": ["es2020", "DOM"],
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"jsxFactory": "h",
|
|
8
|
+
"jsxFragmentFactory": "Fragment",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"incremental": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qwik-todo-express",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Classic Todo MVC app",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "npm run clean && rollup -c",
|
|
7
|
+
"clean": "rimraf */build/",
|
|
8
|
+
"start": "npm run clean && concurrently -c blue,green \"rollup -c --configDev --watch\" \"wait-on public/build && npm run serve\""
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@builder.io/qwik": "~0.0.15",
|
|
12
|
+
"@rollup/plugin-node-resolve": "^13.0.6",
|
|
13
|
+
"@rollup/plugin-typescript": "^8.3.0",
|
|
14
|
+
"concurrently": "^6.4.0",
|
|
15
|
+
"rimraf": "^3.0.2",
|
|
16
|
+
"rollup": "^2.59.0",
|
|
17
|
+
"typescript": "^4.5.2",
|
|
18
|
+
"wait-on": "^6.0.0"
|
|
19
|
+
},
|
|
20
|
+
"author": "Builder.io Team",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=14.14.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
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
|
+
}
|