├── public
├── robots.txt
├── fonts
│ ├── poppins-400.woff2
│ ├── poppins-500.woff2
│ └── poppins-700.woff2
├── manifest.json
└── favicon.svg
├── .env
├── .vscode
└── extensions.json
├── src
├── components
│ ├── starter
│ │ ├── counter
│ │ │ ├── counter.module.css
│ │ │ └── counter.tsx
│ │ ├── infobox
│ │ │ ├── infobox.tsx
│ │ │ └── infobox.module.css
│ │ ├── footer
│ │ │ ├── footer.module.css
│ │ │ └── footer.tsx
│ │ ├── gauge
│ │ │ ├── gauge.module.css
│ │ │ └── index.tsx
│ │ ├── hero
│ │ │ ├── hero.module.css
│ │ │ └── hero.tsx
│ │ ├── header
│ │ │ ├── header.module.css
│ │ │ └── header.tsx
│ │ ├── next-steps
│ │ │ ├── next-steps.module.css
│ │ │ └── next-steps.tsx
│ │ └── icons
│ │ │ └── qwik.tsx
│ └── router-head
│ │ └── router-head.tsx
├── entry.dev.tsx
├── routes
│ ├── layout.tsx
│ ├── service-worker.ts
│ ├── demo
│ │ ├── todolist
│ │ │ ├── todolist.module.css
│ │ │ └── index.tsx
│ │ └── flower
│ │ │ ├── flower.css
│ │ │ └── index.tsx
│ ├── [...index]
│ │ └── index.tsx
│ ├── index.tsx
│ └── styles.css
├── entry.preview.tsx
├── entry.ssr.tsx
├── root.tsx
└── global.css
├── vite.config.ts
├── .gitignore
├── .eslintignore
├── .prettierignore
├── tsconfig.json
├── .eslintrc.cjs
├── package.json
└── README.md
/public/robots.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | BUILDER_PUBLIC_API_KEY=YOUR_API_KEY
--------------------------------------------------------------------------------
/public/fonts/poppins-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/builder-qwik-example/main/public/fonts/poppins-400.woff2
--------------------------------------------------------------------------------
/public/fonts/poppins-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/builder-qwik-example/main/public/fonts/poppins-500.woff2
--------------------------------------------------------------------------------
/public/fonts/poppins-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BuilderIO/builder-qwik-example/main/public/fonts/poppins-700.woff2
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["dbaeumer.vscode-eslint", "unifiedjs.vscode-mdx"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/starter/counter/counter.module.css:
--------------------------------------------------------------------------------
1 | .counter-wrapper {
2 | margin-top: 50px;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | gap: 10px;
7 | }
8 |
9 | @media screen and (min-width: 768px) {
10 | .counter-wrapper {
11 | gap: 30px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/web-manifest-combined.json",
3 | "name": "qwik-project-name",
4 | "short_name": "Welcome to Qwik",
5 | "start_url": ".",
6 | "display": "standalone",
7 | "background_color": "#fff",
8 | "description": "A Qwik project app."
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/starter/infobox/infobox.tsx:
--------------------------------------------------------------------------------
1 | import { Slot, component$ } from '@builder.io/qwik';
2 | import styles from './infobox.module.css';
3 |
4 | export default component$(() => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 | );
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/starter/infobox/infobox.module.css:
--------------------------------------------------------------------------------
1 | .infobox {
2 | color: white;
3 | font-size: 0.8rem;
4 | line-height: 2;
5 | margin: 0 0 40px;
6 | }
7 |
8 | .infobox h3 {
9 | font-size: 1rem;
10 | font-weight: 400;
11 | margin: 0 0 15px;
12 | padding: 0;
13 | }
14 |
15 | .infobox li {
16 | line-height: 2.5;
17 | }
18 |
19 | @media screen and (min-width: 600px) {
20 | .infobox {
21 | margin: 0;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import { qwikVite } from '@builder.io/qwik/optimizer';
3 | import { qwikCity } from '@builder.io/qwik-city/vite';
4 | import tsconfigPaths from 'vite-tsconfig-paths';
5 |
6 | export default defineConfig(() => {
7 | return {
8 | plugins: [qwikCity(), qwikVite(), tsconfigPaths()],
9 | preview: {
10 | headers: {
11 | 'Cache-Control': 'public, max-age=600',
12 | },
13 | },
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/src/components/starter/footer/footer.module.css:
--------------------------------------------------------------------------------
1 | .anchor {
2 | color: white !important;
3 | display: block;
4 | font-size: 0.8rem;
5 | text-align: center;
6 | text-decoration: none;
7 | line-height: 1.5;
8 | }
9 |
10 | .anchor span:not(.spacer) {
11 | display: block;
12 | }
13 |
14 | .spacer {
15 | display: none;
16 | padding: 0 15px;
17 | }
18 |
19 | @media screen and (min-width: 768px) {
20 | .anchor span {
21 | display: inline !important;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/starter/gauge/gauge.module.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | position: relative;
3 | }
4 |
5 | .gauge {
6 | width: 160px;
7 | }
8 |
9 | .value {
10 | position: absolute;
11 | top: 50%;
12 | left: 50%;
13 | color: white;
14 | font-size: 3rem;
15 | transform: translate(-50%, -50%);
16 | width: 200px;
17 | text-align: center;
18 | }
19 |
20 | @media screen and (min-width: 768px) {
21 | .gauge {
22 | width: 400px;
23 | }
24 | .value {
25 | font-size: 7rem;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build
2 | /dist
3 | /lib
4 | /lib-types
5 | /server
6 |
7 | # Development
8 | node_modules
9 | *.local
10 |
11 | # Cache
12 | .cache
13 | .mf
14 | .rollup.cache
15 | tsconfig.tsbuildinfo
16 |
17 | # Logs
18 | logs
19 | *.log
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 | pnpm-debug.log*
24 | lerna-debug.log*
25 |
26 | # Editor
27 | .vscode/*
28 | !.vscode/extensions.json
29 | .idea
30 | .DS_Store
31 | *.suo
32 | *.ntvs*
33 | *.njsproj
34 | *.sln
35 | *.sw?
36 |
37 | # Yarn
38 | .yarn/*
39 | !.yarn/releases
40 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*.log
2 | **/.DS_Store
3 | *.
4 | .vscode/settings.json
5 | .history
6 | .yarn
7 | bazel-*
8 | bazel-bin
9 | bazel-out
10 | bazel-qwik
11 | bazel-testlogs
12 | dist
13 | dist-dev
14 | lib
15 | lib-types
16 | etc
17 | external
18 | node_modules
19 | temp
20 | tsc-out
21 | tsdoc-metadata.json
22 | target
23 | output
24 | rollup.config.js
25 | build
26 | .cache
27 | .vscode
28 | .rollup.cache
29 | dist
30 | tsconfig.tsbuildinfo
31 | vite.config.ts
32 | *.spec.tsx
33 | *.spec.ts
34 | .netlify
35 | pnpm-lock.yaml
36 | package-lock.json
37 | yarn.lock
38 | server
39 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.log
2 | **/.DS_Store
3 | *.
4 | .vscode/settings.json
5 | .history
6 | .yarn
7 | bazel-*
8 | bazel-bin
9 | bazel-out
10 | bazel-qwik
11 | bazel-testlogs
12 | dist
13 | dist-dev
14 | lib
15 | lib-types
16 | etc
17 | external
18 | node_modules
19 | temp
20 | tsc-out
21 | tsdoc-metadata.json
22 | target
23 | output
24 | rollup.config.js
25 | build
26 | .cache
27 | .vscode
28 | .rollup.cache
29 | dist
30 | tsconfig.tsbuildinfo
31 | vite.config.ts
32 | *.spec.tsx
33 | *.spec.ts
34 | .netlify
35 | pnpm-lock.yaml
36 | package-lock.json
37 | yarn.lock
38 | server
39 |
--------------------------------------------------------------------------------
/src/components/starter/hero/hero.module.css:
--------------------------------------------------------------------------------
1 | .hero {
2 | display: flex;
3 | vertical-align: middle;
4 | flex-direction: column;
5 | flex-wrap: nowrap;
6 | align-items: center;
7 | height: 450px;
8 | justify-content: center;
9 | gap: 40px;
10 | }
11 |
12 | .hero p {
13 | color: white;
14 | margin: 0;
15 | font-size: 1rem;
16 | }
17 |
18 | .button-group {
19 | display: flex;
20 | flex-direction: row;
21 | gap: 24px;
22 | }
23 |
24 | @media screen and (min-width: 768px) {
25 | .hero {
26 | gap: 60px;
27 | height: 500px;
28 | }
29 |
30 | .hero p {
31 | font-size: 1.3rem;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/starter/footer/footer.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import { useServerTimeLoader } from '~/routes/layout';
3 | import styles from './footer.module.css';
4 |
5 | export default component$(() => {
6 | const serverTime = useServerTimeLoader();
7 |
8 | return (
9 |
18 | );
19 | });
20 |
--------------------------------------------------------------------------------
/src/entry.dev.tsx:
--------------------------------------------------------------------------------
1 | /*
2 | * WHAT IS THIS FILE?
3 | *
4 | * Development entry point using only client-side modules:
5 | * - Do not use this mode in production!
6 | * - No SSR
7 | * - No portion of the application is pre-rendered on the server.
8 | * - All of the application is running eagerly in the browser.
9 | * - More code is transferred to the browser than in SSR mode.
10 | * - Optimizer/Serialization/Deserialization code is not exercised!
11 | */
12 | import { render, type RenderOptions } from '@builder.io/qwik';
13 | import Root from './root';
14 |
15 | export default function (opts: RenderOptions) {
16 | return render(document, , opts);
17 | }
18 |
--------------------------------------------------------------------------------
/src/routes/layout.tsx:
--------------------------------------------------------------------------------
1 | import { component$, Slot, useStyles$ } from '@builder.io/qwik';
2 | import { routeLoader$ } from '@builder.io/qwik-city';
3 |
4 | import Header from '~/components/starter/header/header';
5 | import Footer from '~/components/starter/footer/footer';
6 |
7 | import styles from './styles.css?inline';
8 |
9 | export const useServerTimeLoader = routeLoader$(() => {
10 | return {
11 | date: new Date().toISOString(),
12 | };
13 | });
14 |
15 | export default component$(() => {
16 | useStyles$(styles);
17 | return (
18 | <>
19 |
20 |
21 |
22 |
23 |
24 | >
25 | );
26 | });
27 |
--------------------------------------------------------------------------------
/src/entry.preview.tsx:
--------------------------------------------------------------------------------
1 | /*
2 | * WHAT IS THIS FILE?
3 | *
4 | * It's the bundle entry point for `npm run preview`.
5 | * That is, serving your app built in production mode.
6 | *
7 | * Feel free to modify this file, but don't remove it!
8 | *
9 | * Learn more about Vite's preview command:
10 | * - https://vitejs.dev/config/preview-options.html#preview-options
11 | *
12 | */
13 | import { createQwikCity } from '@builder.io/qwik-city/middleware/node';
14 | import qwikCityPlan from '@qwik-city-plan';
15 | import render from './entry.ssr';
16 |
17 | /**
18 | * The default export is the QwikCity adapter used by Vite preview.
19 | */
20 | export default createQwikCity({ render, qwikCityPlan });
21 |
--------------------------------------------------------------------------------
/src/routes/service-worker.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * WHAT IS THIS FILE?
3 | *
4 | * The service-worker.ts file is used to have state of the art prefetching.
5 | * https://qwik.builder.io/qwikcity/prefetching/overview/
6 | *
7 | * Qwik uses a service worker to speed up your site and reduce latency, ie, not used in the traditional way of offline.
8 | * You can also use this file to add more functionality that runs in the service worker.
9 | */
10 | import { setupServiceWorker } from '@builder.io/qwik-city/service-worker';
11 |
12 | setupServiceWorker();
13 |
14 | addEventListener('install', () => self.skipWaiting());
15 |
16 | addEventListener('activate', () => self.clients.claim());
17 |
18 | declare const self: ServiceWorkerGlobalScope;
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "target": "ES2017",
5 | "module": "ES2022",
6 | "lib": ["es2020", "DOM", "WebWorker", "DOM.Iterable"],
7 | "jsx": "react-jsx",
8 | "jsxImportSource": "@builder.io/qwik",
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "resolveJsonModule": true,
12 | "moduleResolution": "node",
13 | "esModuleInterop": true,
14 | "skipLibCheck": true,
15 | "incremental": true,
16 | "isolatedModules": true,
17 | "outDir": "tmp",
18 | "noEmit": true,
19 | "types": ["node", "vite/client"],
20 | "paths": {
21 | "~/*": ["./src/*"]
22 | }
23 | },
24 | "files": ["./.eslintrc.cjs"],
25 | "include": ["src", "./*.d.ts"]
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/starter/header/header.module.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | display: flex;
3 | align-items: center;
4 | justify-content: space-between;
5 | }
6 |
7 | .logo {
8 | display: inline-block;
9 | }
10 | .logo a {
11 | display: block;
12 | }
13 |
14 | .header ul {
15 | margin: 0;
16 | padding: 0;
17 | list-style: none;
18 | display: flex;
19 | gap: 30px;
20 | }
21 |
22 | .header li {
23 | display: none;
24 | margin: 0;
25 | padding: 0;
26 | font-size: 0.7rem;
27 | }
28 |
29 | .header li a {
30 | color: white;
31 | display: inline-block;
32 | padding: 0;
33 | text-decoration: none;
34 | }
35 |
36 | .header li a:hover {
37 | color: var(--qwik-light-blue);
38 | }
39 |
40 | @media (min-width: 450px) {
41 | .header li {
42 | display: inline-block;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/routes/demo/todolist/todolist.module.css:
--------------------------------------------------------------------------------
1 | .list {
2 | display: flex;
3 | flex-direction: column;
4 | gap: 20px;
5 | color: white;
6 | }
7 |
8 | .list,
9 | .empty {
10 | min-height: 250px;
11 | }
12 |
13 | .list li {
14 | list-style: none;
15 | }
16 |
17 | .empty {
18 | color: white;
19 | display: block;
20 | }
21 |
22 | .input {
23 | background: white;
24 | color: var(--qwik-light-blue);
25 | border: none;
26 | border-radius: 8px;
27 | padding: 15px 20px;
28 | margin-right: 10px;
29 | font-size: 0.8rem;
30 | }
31 |
32 | .hint {
33 | font-size: 0.8rem;
34 | color: white;
35 | margin-top: 30px;
36 | }
37 |
38 | @media screen and (min-width: 768px) {
39 | .input {
40 | padding: 23px 35px;
41 | margin-right: 20px;
42 | font-size: 1rem;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/starter/next-steps/next-steps.module.css:
--------------------------------------------------------------------------------
1 | .gettingstarted {
2 | display: flex;
3 | color: white;
4 | flex-direction: column;
5 | justify-content: center;
6 | align-items: center;
7 | height: 280px;
8 | line-height: 1.5;
9 | gap: 10px;
10 | max-width: 600px;
11 | margin: 0 auto;
12 | }
13 |
14 | .gettingstarted .intro {
15 | font-size: 1rem;
16 | width: 100%;
17 | word-break: break-word;
18 | }
19 | .gettingstarted .hint {
20 | font-size: 0.8rem;
21 | }
22 | .gettingstarted .hint a {
23 | color: var(--qwik-dark-purple);
24 | }
25 |
26 | @media screen and (min-width: 768px) {
27 | .gettingstarted {
28 | height: 180px;
29 | }
30 | .gettingstarted .intro {
31 | font-size: 1.2rem;
32 | }
33 | .gettingstarted .hint {
34 | font-size: 1rem;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/starter/counter/counter.tsx:
--------------------------------------------------------------------------------
1 | import { component$, useSignal, $ } from '@builder.io/qwik';
2 | import styles from './counter.module.css';
3 | import Gauge from '../gauge';
4 |
5 | export default component$(() => {
6 | const count = useSignal(70);
7 |
8 | const setCount = $((newValue: number) => {
9 | if (newValue < 0 || newValue > 100) {
10 | return;
11 | }
12 | count.value = newValue;
13 | });
14 |
15 | return (
16 |
17 | setCount(count.value - 1)}>
18 | -
19 |
20 |
21 | setCount(count.value + 1)}>
22 | +
23 |
24 |
25 | );
26 | });
27 |
--------------------------------------------------------------------------------
/src/entry.ssr.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * WHAT IS THIS FILE?
3 | *
4 | * SSR entry point, in all cases the application is render outside the browser, this
5 | * entry point will be the common one.
6 | *
7 | * - Server (express, cloudflare...)
8 | * - npm run start
9 | * - npm run preview
10 | * - npm run build
11 | *
12 | */
13 | import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server';
14 | import { manifest } from '@qwik-client-manifest';
15 | import Root from './root';
16 |
17 | export default function (opts: RenderToStreamOptions) {
18 | return renderToStream( , {
19 | manifest,
20 | ...opts,
21 | // Use container attributes to set attributes on the html tag.
22 | containerAttributes: {
23 | lang: 'en-us',
24 | ...opts.containerAttributes,
25 | },
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/src/root.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import { QwikCityProvider, RouterOutlet, ServiceWorkerRegister } from '@builder.io/qwik-city';
3 | import { RouterHead } from './components/router-head/router-head';
4 |
5 | import './global.css';
6 |
7 | export default component$(() => {
8 | /**
9 | * The root of a QwikCity site always start with the component,
10 | * immediately followed by the document's and .
11 | *
12 | * Dont remove the `` and `` elements.
13 | */
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | });
29 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/router-head/router-head.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import { useDocumentHead, useLocation } from '@builder.io/qwik-city';
3 |
4 | /**
5 | * The RouterHead component is placed inside of the document `` element.
6 | */
7 | export const RouterHead = component$(() => {
8 | const head = useDocumentHead();
9 | const loc = useLocation();
10 |
11 | return (
12 | <>
13 | {head.title}
14 |
15 |
16 |
17 |
18 |
19 | {head.meta.map((m) => (
20 |
21 | ))}
22 |
23 | {head.links.map((l) => (
24 |
25 | ))}
26 |
27 | {head.styles.map((s) => (
28 |
29 | ))}
30 | >
31 | );
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/starter/header/header.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import { QwikLogo } from '../icons/qwik';
3 | import styles from './header.module.css';
4 |
5 | export default component$(() => {
6 | return (
7 |
33 | );
34 | });
35 |
--------------------------------------------------------------------------------
/src/components/starter/gauge/index.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import styles from './gauge.module.css';
3 |
4 | export default component$(({ value = 50 }: { value?: number }) => {
5 | const safeValue = value < 0 || value > 100 ? 50 : value;
6 |
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
28 |
29 | {safeValue}
30 |
31 | );
32 | });
33 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | es2021: true,
6 | node: true,
7 | },
8 | extends: [
9 | 'eslint:recommended',
10 | 'plugin:@typescript-eslint/recommended',
11 | 'plugin:qwik/recommended',
12 | ],
13 | parser: '@typescript-eslint/parser',
14 | parserOptions: {
15 | tsconfigRootDir: __dirname,
16 | project: ['./tsconfig.json'],
17 | ecmaVersion: 2021,
18 | sourceType: 'module',
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | },
23 | plugins: ['@typescript-eslint'],
24 | rules: {
25 | '@typescript-eslint/no-explicit-any': 'off',
26 | '@typescript-eslint/explicit-module-boundary-types': 'off',
27 | '@typescript-eslint/no-inferrable-types': 'off',
28 | '@typescript-eslint/no-non-null-assertion': 'off',
29 | '@typescript-eslint/no-empty-interface': 'off',
30 | '@typescript-eslint/no-namespace': 'off',
31 | '@typescript-eslint/no-empty-function': 'off',
32 | '@typescript-eslint/no-this-alias': 'off',
33 | '@typescript-eslint/ban-types': 'off',
34 | '@typescript-eslint/ban-ts-comment': 'off',
35 | 'prefer-spread': 'off',
36 | 'no-case-declarations': 'off',
37 | 'no-console': 'off',
38 | '@typescript-eslint/no-unused-vars': ['error'],
39 | '@typescript-eslint/consistent-type-imports': 'warn',
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-qwik-basic-starter",
3 | "description": "App with Routing built-in (recommended)",
4 | "engines": {
5 | "node": ">=15.0.0"
6 | },
7 | "private": true,
8 | "scripts": {
9 | "build": "qwik build",
10 | "build.client": "vite build",
11 | "build.preview": "vite build --ssr src/entry.preview.tsx",
12 | "build.types": "tsc --incremental --noEmit",
13 | "deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'",
14 | "dev": "vite --mode ssr",
15 | "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
16 | "fmt": "prettier --write .",
17 | "fmt.check": "prettier --check .",
18 | "lint": "eslint \"src/**/*.ts*\"",
19 | "preview": "qwik build preview && vite preview --open",
20 | "start": "vite --open --mode ssr",
21 | "qwik": "qwik"
22 | },
23 | "devDependencies": {
24 | "@builder.io/qwik": "0.106.0",
25 | "@builder.io/qwik-city": "^0.106.0",
26 | "@types/eslint": "8.37.0",
27 | "@types/node": "^18.16.1",
28 | "@typescript-eslint/eslint-plugin": "5.59.1",
29 | "@typescript-eslint/parser": "5.59.1",
30 | "eslint": "8.39.0",
31 | "eslint-plugin-qwik": "0.106.0",
32 | "prettier": "2.8.8",
33 | "typescript": "5.0.4",
34 | "undici": "5.22.0",
35 | "vite": "4.3.3",
36 | "vite-tsconfig-paths": "4.2.0"
37 | },
38 | "dependencies": {
39 | "@builder.io/sdk-qwik": "^0.2.3"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/global.css:
--------------------------------------------------------------------------------
1 | /**
2 | * WHAT IS THIS FILE?
3 | *
4 | * Globally applied styles. No matter which components are in the page or matching route,
5 | * the styles in here will be applied to the Document, without any sort of CSS scoping.
6 | *
7 | */
8 |
9 | :root {
10 | --qwik-dark-blue: #006ce9;
11 | --qwik-light-blue: #18b6f6;
12 | --qwik-light-purple: #ac7ff4;
13 | --qwik-dark-purple: #713fc2;
14 | --qwik-dirty-black: #1d2033;
15 | --qwik-dark-background: #151934;
16 | --qwik-dark-text: #ffffff;
17 | }
18 |
19 | html {
20 | line-height: 1;
21 | -webkit-text-size-adjust: 100%;
22 | -moz-tab-size: 4;
23 | -o-tab-size: 4;
24 | tab-size: 4;
25 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
26 | 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
27 | 'Segoe UI Symbol', 'Noto Color Emoji';
28 | }
29 |
30 | body {
31 | padding: 0;
32 | margin: 0;
33 | line-height: inherit;
34 | }
35 |
36 | /**
37 | * WHAT IS THIS FILE?
38 | *
39 | * Globally applied styles. No matter which components are in the page or matching route,
40 | * the styles in here will be applied to the Document, without any sort of CSS scoping.
41 | *
42 | */
43 | html {
44 | -webkit-text-size-adjust: 100%;
45 | -moz-tab-size: 4;
46 | -o-tab-size: 4;
47 | tab-size: 4;
48 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
49 | 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
50 | 'Segoe UI Symbol', 'Noto Color Emoji';
51 | }
52 |
53 | body {
54 | padding: 0;
55 | line-height: inherit;
56 | }
57 |
--------------------------------------------------------------------------------
/src/routes/demo/flower/flower.css:
--------------------------------------------------------------------------------
1 | .host {
2 | display: grid;
3 |
4 | align-items: center;
5 | justify-content: center;
6 | justify-items: center;
7 | --rotation: 135deg;
8 | --rotation: 225deg;
9 | --size-step: 10px;
10 | --odd-color-step: 5;
11 | --even-color-step: 5;
12 | --center: 12;
13 |
14 | width: 100%;
15 | height: 500px;
16 |
17 | contain: strict;
18 | }
19 |
20 | h1 {
21 | margin-bottom: 60px;
22 | }
23 |
24 | .input {
25 | width: 60%;
26 | }
27 |
28 | .square {
29 | --size: calc(40px + var(--index) * var(--size-step));
30 |
31 | display: block;
32 | width: var(--size);
33 | height: var(--size);
34 | transform: rotateZ(calc(var(--rotation) * var(--state) * (var(--center) - var(--index))));
35 | transition-property: transform, border-color;
36 | transition-duration: 5s;
37 | transition-timing-function: ease-in-out;
38 | grid-area: 1 / 1;
39 | background: white;
40 | border-width: 2px;
41 | border-style: solid;
42 | border-color: black;
43 | box-sizing: border-box;
44 | will-change: transform, border-color;
45 |
46 | contain: strict;
47 | }
48 |
49 | .square.odd {
50 | --luminance: calc(1 - calc(calc(var(--index) * var(--odd-color-step)) / 256));
51 | background: rgb(
52 | calc(172 * var(--luminance)),
53 | calc(127 * var(--luminance)),
54 | calc(244 * var(--luminance))
55 | );
56 | }
57 |
58 | .pride .square:nth-child(12n + 1) {
59 | background: #e70000;
60 | }
61 | .pride .square:nth-child(12n + 3) {
62 | background: #ff8c00;
63 | }
64 | .pride .square:nth-child(12n + 5) {
65 | background: #ffef00;
66 | }
67 | .pride .square:nth-child(12n + 7) {
68 | background: #00811f;
69 | }
70 | .pride .square:nth-child(12n + 9) {
71 | background: #0044ff;
72 | }
73 | .pride .square:nth-child(12n + 11) {
74 | background: #760089;
75 | }
76 |
--------------------------------------------------------------------------------
/src/routes/demo/flower/index.tsx:
--------------------------------------------------------------------------------
1 | import { component$, useVisibleTask$, useStore, useStylesScoped$ } from '@builder.io/qwik';
2 | import { type DocumentHead, useLocation } from '@builder.io/qwik-city';
3 | import styles from './flower.css?inline';
4 |
5 | export default component$(() => {
6 | useStylesScoped$(styles);
7 | const loc = useLocation();
8 |
9 | const state = useStore({
10 | count: 0,
11 | number: 20,
12 | });
13 |
14 | useVisibleTask$(({ cleanup }) => {
15 | const timeout = setTimeout(() => (state.count = 1), 500);
16 | cleanup(() => clearTimeout(timeout));
17 |
18 | const internal = setInterval(() => state.count++, 7000);
19 | cleanup(() => clearInterval(internal));
20 | });
21 |
22 | return (
23 |
24 |
25 |
26 | Generate Flowers
27 |
28 |
29 |
{
35 | state.number = (ev.target as HTMLInputElement).valueAsNumber;
36 | }}
37 | />
38 |
47 | {Array.from({ length: state.number }, (_, i) => (
48 |
56 | )).reverse()}
57 |
58 |
59 | );
60 | });
61 |
62 | export const head: DocumentHead = {
63 | title: 'Qwik Flower',
64 | };
65 |
--------------------------------------------------------------------------------
/src/routes/demo/todolist/index.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import {
3 | type DocumentHead,
4 | routeLoader$,
5 | routeAction$,
6 | zod$,
7 | z,
8 | Form,
9 | } from '@builder.io/qwik-city';
10 | import styles from './todolist.module.css';
11 |
12 | interface ListItem {
13 | text: string;
14 | }
15 |
16 | export const list: ListItem[] = [];
17 |
18 | export const useListLoader = routeLoader$(() => {
19 | return list;
20 | });
21 |
22 | export const useAddToListAction = routeAction$(
23 | (item) => {
24 | list.push(item);
25 | return {
26 | success: true,
27 | };
28 | },
29 | zod$({
30 | text: z.string().trim().min(1),
31 | })
32 | );
33 |
34 | export default component$(() => {
35 | const list = useListLoader();
36 | const action = useAddToListAction();
37 |
38 | return (
39 | <>
40 |
41 |
42 | TODO List
43 |
44 |
45 |
46 |
47 |
48 |
49 | {(list.value.length && (
50 |
51 | {list.value.map((item, index) => (
52 | {item.text}
53 | ))}
54 |
55 | )) ||
No items found }
56 |
57 |
58 |
59 |
65 |
66 |
PS: This little app works even when JavaScript is disabled.
67 |
68 | >
69 | );
70 | });
71 |
72 | export const head: DocumentHead = {
73 | title: 'Qwik Todo List',
74 | };
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Builder.io example with Qwik
2 |
3 | An exaple of using [Builder.io's](https://www.builder.io) drag and drop headless CMS with Qwik.
4 |
5 | See [src/routes[...index]/index.tsx](src/routes[...index]/index.tsx) for the integration code.
6 |
7 | ## How to use
8 |
9 | Clone and install:
10 |
11 | ```bash
12 | git clone https://github.com/BuilderIO/builder-qwik-example.git
13 | cd builder-qwik-example
14 | ```
15 |
16 | Create a free [Builder.io account](https://builder.io/signup) (only takes a couple minutes), and paste your [public API key](https://www.builder.io/c/docs/using-your-api-key) into `.env`
17 |
18 | ```diff
19 | - BUILDER_PUBLIC_API_KEY=YOUR_API_KEY
20 | + BUILDER_PUBLIC_API_KEY=abc123
21 | ```
22 |
23 | Then run the development server:
24 |
25 | ```bash
26 | npm run dev
27 | ```
28 |
29 | Now, go set your [preview URL](https://www.builder.io/c/docs/guides/preview-url) to `http://localhost:5173/`
30 |
31 | 1. Go to [https://builder.io/models](builder.io/models)
32 | 2. Choose the `page` model
33 | 3. Set the preview URL to `http://localhost:5173/` and click `save` in the top right
34 |
35 | Now, let's create a page in Builder.io and see it live in Qwik!
36 |
37 | 1. Go to [https://builder.io/content](builder.io/content)
38 | 2. Click `+ New` and choose `Page`
39 | 3. Give it a name and click `Create`
40 |
41 | Now, try out the visual editor! You can find a custom Qwik components
42 | in the `Custom Components` section of the insert tab.
43 |
44 | You may also choose to limit visual editing to only your custom components with [components-only mode](https://www.builder.io/c/docs/guides/components-only-mode).
45 |
46 | ## Next Steps
47 |
48 | See our full integration guides [here](https://www.builder.io/c/docs/developers)
49 |
50 | Also, when you push your integration to production, go back and update your preview URL to your production URL so now anyone on your team can visuall create content in your Qwik app!
51 |
52 | Also, to integrate structured data, see [this guide](https://www.builder.io/c/docs/integrate-cms-data)
53 |
--------------------------------------------------------------------------------
/src/components/starter/hero/hero.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import styles from './hero.module.css';
3 |
4 | export default component$(() => {
5 | return (
6 |
7 |
8 | So fantastic
9 |
10 | to have you here
11 |
12 |
Have fun building your App with Qwik.
13 |
73 |
74 | );
75 | });
76 |
--------------------------------------------------------------------------------
/src/routes/[...index]/index.tsx:
--------------------------------------------------------------------------------
1 | import { component$, useStore } from "@builder.io/qwik";
2 | import { routeLoader$ } from "@builder.io/qwik-city";
3 | import {
4 | getContent,
5 | RenderContent,
6 | getBuilderSearchParams,
7 | type RegisteredComponent,
8 | } from "@builder.io/sdk-qwik";
9 |
10 | export const BUILDER_PUBLIC_API_KEY = process.env.BUILDER_PUBLIC_API_KEY!; // <-- Add your key in .env
11 | export const BUILDER_MODEL = "page";
12 |
13 | // Example component to use the in the drag and drop editor
14 | // https://www.builder.io/c/docs/custom-components-setup
15 | export const MyFunComponent = component$((props: { text: string }) => {
16 | const state = useStore({
17 | count: 0,
18 | });
19 |
20 | return (
21 |
22 |
{props.text.toUpperCase()}
23 |
{state.count}
24 |
state.count++}>Click me
25 |
26 | );
27 | });
28 |
29 | // You will find these components in the "custom components"
30 | // section of the visual editor
31 | // You can also turn on "components only mode" to limit
32 | // editing to only these components
33 | // https://www.builder.io/c/docs/guides/components-only-mode
34 | export const CUSTOM_COMPONENTS: RegisteredComponent[] = [
35 | {
36 | component: MyFunComponent,
37 | name: "MyFunComponent",
38 | inputs: [
39 | {
40 | name: "text",
41 | type: "string",
42 | defaultValue: "Hello world",
43 | },
44 | ],
45 | },
46 | ];
47 |
48 | // Use Qwik City's `useBuilderContent` to get your content from Builder.
49 | // `routeLoader$()` takes an async function to fetch content
50 | // from Builder with `getContent()`.
51 | export const useBuilderContent = routeLoader$(async ({ url, error }) => {
52 | const isPreviewing = url.searchParams.has("builder.preview");
53 |
54 | const builderContent = await getContent({
55 | model: BUILDER_MODEL,
56 | apiKey: BUILDER_PUBLIC_API_KEY,
57 | options: getBuilderSearchParams(url.searchParams),
58 | userAttributes: {
59 | urlPath: url.pathname,
60 | },
61 | });
62 |
63 | // If there's no content, throw a 404.
64 | // You can use your own 404 component here
65 | if (!builderContent && !isPreviewing) {
66 | throw error(404, "Page not found");
67 | }
68 | // return content fetched from Builder, which is JSON
69 | return builderContent;
70 | });
71 |
72 | export default component$(() => {
73 | const content = useBuilderContent();
74 |
75 | // RenderContent uses `content` to
76 | // render the content of the given model, here a page,
77 | // of your space (specified by the API Key)
78 | return (
79 |
85 | );
86 | });
87 |
--------------------------------------------------------------------------------
/src/components/starter/icons/qwik.tsx:
--------------------------------------------------------------------------------
1 | export const QwikLogo = ({ width = 100, height = 35 }: { width?: number; height?: number }) => (
2 |
9 |
13 |
17 |
21 |
25 |
29 |
33 |
37 |
38 | );
39 |
--------------------------------------------------------------------------------
/src/components/starter/next-steps/next-steps.tsx:
--------------------------------------------------------------------------------
1 | import { component$, $, useOnWindow, useSignal } from '@builder.io/qwik';
2 | import styles from './next-steps.module.css';
3 |
4 | export const GETTING_STARTED_STEPS = [
5 | {
6 | message: "Press and hold the ALT key to active 'Click-to-Source' mode",
7 | },
8 | {
9 | message: 'Select the title of this page while keeping the ALT key pressed',
10 | hint: 'Edit the title and save the changes. If your editor does not open, have a look at this page to set the correct LAUNCH_EDITOR value.',
11 | },
12 | {
13 | message:
14 | 'Update now the routeLoader$ defined in the src/routes//layout.tsx file',
15 | hint: 'Instead of returning the current date, you could return any possible string. The output is displayed in the footer.',
16 | },
17 | {
18 | message: 'Create a new Route called /me',
19 | hint: 'Create a new directory called me in src/routes. Within this directory create a index.tsx file or copy the src/routes/index.tsx file. Your new route is now accessible here ✨',
20 | },
21 | {
22 | message: 'Time to have a look at Forms ',
23 | hint: 'Open the TODO list App and add some items to the list. Try the same with disabled JavaScript 🐰',
24 | },
25 | {
26 | message: 'Congratulations! You are now familiar with the basics! 🎉',
27 | hint: "If you need further info on how to use qwik, have a look at qwik.builder.io or join the Discord channel .",
28 | },
29 | ];
30 |
31 | export default component$(() => {
32 | const gettingStartedStep = useSignal(0);
33 |
34 | useOnWindow(
35 | 'keydown',
36 | $((e) => {
37 | if ((e as KeyboardEvent).key === 'Alt') {
38 | gettingStartedStep.value = 1;
39 | }
40 | })
41 | );
42 |
43 | return (
44 |
45 |
46 | Time for a quick
47 |
48 | qwik intro ?
49 |
50 |
60 | {gettingStartedStep.value + 1 < GETTING_STARTED_STEPS.length ? (
61 |
gettingStartedStep.value++}>
62 | Continue with Step {gettingStartedStep.value + 2} of {GETTING_STARTED_STEPS.length}
63 |
64 | ) : (
65 |
(gettingStartedStep.value = 0)}>
66 | Re-Start
67 |
68 | )}
69 |
70 | );
71 | });
72 |
--------------------------------------------------------------------------------
/src/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import { component$ } from '@builder.io/qwik';
2 | import type { DocumentHead } from '@builder.io/qwik-city';
3 |
4 | import Counter from '~/components/starter/counter/counter';
5 | import Hero from '~/components/starter/hero/hero';
6 | import Infobox from '~/components/starter/infobox/infobox';
7 | import Starter from '~/components/starter/next-steps/next-steps';
8 |
9 | export default component$(() => {
10 | return (
11 | <>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | You can count
21 | on me
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | CLI Commands
30 |
31 | <>
32 |
33 | npm run dev
34 |
35 | Starts the development server and watches for changes
36 |
37 |
38 | npm run preview
39 |
40 | Creates production build and starts a server to preview it
41 |
42 |
43 | npm run build
44 |
45 | Creates production build
46 |
47 |
48 | npm run qwik add
49 |
50 | Runs the qwik CLI to add integrations
51 |
52 | >
53 |
54 |
55 |
56 |
57 |
58 | Example Apps
59 |
60 |
61 | Have a look at the Flower App or the{' '}
62 | Todo App .
63 |
64 |
65 |
66 |
67 |
70 |
97 |
98 |
99 |
100 | >
101 | );
102 | });
103 |
104 | export const head: DocumentHead = {
105 | title: 'Welcome to Qwik',
106 | meta: [
107 | {
108 | name: 'description',
109 | content: 'Qwik site description',
110 | },
111 | ],
112 | };
113 |
--------------------------------------------------------------------------------
/src/routes/styles.css:
--------------------------------------------------------------------------------
1 | /* THIS FILE IS JUST FOR EXAMPLES, DELETE IT IF YOU DON'T NEED IT */
2 |
3 | /* SHELL ---------------------------------------- */
4 | html {
5 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
6 | 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
7 | 'Segoe UI Symbol', 'Noto Color Emoji';
8 | }
9 |
10 | body {
11 | background: var(--qwik-dark-background);
12 | color: var(--qwik-dark-text);
13 | overflow-x: hidden;
14 | }
15 |
16 | /* HEADINGS ------------------------------------- */
17 | h1,
18 | h2,
19 | h3 {
20 | color: white;
21 | margin: 0;
22 | }
23 |
24 | h1 {
25 | font-size: 3.2rem;
26 | text-align: center;
27 | }
28 | h1 .highlight,
29 | h3 .highlight {
30 | color: var(--qwik-light-blue);
31 | }
32 |
33 | h2 {
34 | font-weight: 400;
35 | font-size: 2.4rem;
36 | }
37 | h2 .highlight {
38 | font-weight: 700;
39 | }
40 |
41 | h3 {
42 | font-size: 2rem;
43 | }
44 |
45 | @media screen and (min-width: 768px) {
46 | h1 {
47 | font-size: 5rem;
48 | }
49 | h2 {
50 | font-size: 3.4rem;
51 | }
52 | h3 {
53 | font-size: 3rem;
54 | }
55 | }
56 |
57 | /* TAGS ----------------------------------------- */
58 | a {
59 | text-decoration: none;
60 | color: var(--qwik-light-blue);
61 | }
62 |
63 | code {
64 | background: rgba(230, 230, 230, 0.3);
65 | border-radius: 4px;
66 | padding: 2px 6px;
67 | }
68 |
69 | ul {
70 | margin: 0;
71 | padding-left: 20px;
72 | }
73 |
74 | /* CONTAINER ------------------------------------ */
75 | .container {
76 | margin: 0 auto;
77 | padding: 30px 40px;
78 | }
79 | .container.container-purple {
80 | background: var(--qwik-light-purple);
81 | }
82 | .container.container-dark {
83 | background: var(--qwik-dark-background);
84 | color: var(--qwik-dark-text);
85 | }
86 | .container.container-center {
87 | text-align: center;
88 | }
89 | .container.container-flex {
90 | /* does nothing on mobile */
91 | }
92 | .container.container-spacing-xl {
93 | padding: 50px 40px;
94 | }
95 |
96 | @media screen and (min-width: 768px) {
97 | .container {
98 | padding: 50px 80px;
99 | }
100 | .container.container-spacing-xl {
101 | padding: 100px 60px;
102 | }
103 | .container.container-flex {
104 | display: flex;
105 | justify-content: center;
106 | gap: 60px;
107 | }
108 | }
109 |
110 | /* BUTTONS -------------------------------------- */
111 | a.button,
112 | button {
113 | background: var(--qwik-light-blue);
114 | border: none;
115 | border-radius: 8px;
116 | color: white;
117 | cursor: pointer;
118 | font-size: 0.8rem;
119 | padding: 15px 20px;
120 | text-align: center;
121 | }
122 |
123 | a.button.button-dark,
124 | button.button-dark {
125 | background: var(--qwik-dirty-black);
126 | }
127 |
128 | a.button.button-small,
129 | button.button-small {
130 | padding: 15px 25px;
131 | }
132 |
133 | @media screen and (min-width: 768px) {
134 | a.button,
135 | button {
136 | font-size: 1rem;
137 | padding: 23px 35px;
138 | }
139 | }
140 |
141 | /* DESIGN --------------------------------------- */
142 | .ellipsis {
143 | position: absolute;
144 | top: 100px;
145 | left: -100px;
146 | width: 400px;
147 | height: 400px;
148 | background: radial-gradient(
149 | 57.58% 57.58% at 48.79% 42.42%,
150 | rgba(24, 180, 244, 0.5) 0%,
151 | rgba(46, 55, 114, 0) 63.22%
152 | );
153 | transform: rotate(5deg);
154 | opacity: 0.5;
155 | z-index: -1;
156 | }
157 | .ellipsis.ellipsis-purple {
158 | top: 1350px;
159 | left: -100px;
160 | background: radial-gradient(
161 | 50% 50% at 50% 50%,
162 | rgba(172, 127, 244, 0.5) 0%,
163 | rgba(21, 25, 52, 0) 100%
164 | );
165 | transform: rotate(-5deg);
166 | }
167 |
168 | @media screen and (min-width: 768px) {
169 | .ellipsis {
170 | top: -100px;
171 | left: 350px;
172 | width: 1400px;
173 | height: 800px;
174 | }
175 | .ellipsis.ellipsis-purple {
176 | top: 1300px;
177 | left: -200px;
178 | }
179 | }
180 |
181 | /* used icon pack: https://www.svgrepo.com/collection/phosphor-thin-icons */
182 | .icon:before {
183 | width: 18px;
184 | height: 18px;
185 | content: '';
186 | display: inline-block;
187 | margin-right: 20px;
188 | position: relative;
189 | top: 2px;
190 | }
191 |
192 | .icon-cli:before {
193 | 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");
194 | }
195 |
196 | .icon-apps:before {
197 | 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");
198 | }
199 |
200 | .icon-community:before {
201 | 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");
202 | }
203 |
--------------------------------------------------------------------------------