├── .gitignore
├── LICENSE
├── README.md
├── cli.ts
├── imports
├── fmt.ts
├── fs.ts
└── path.ts
├── src
├── cli
│ ├── create.ts
│ ├── io.ts
│ ├── prompt.ts
│ └── templates.ts
└── shared
│ ├── encoder.ts
│ ├── log.ts
│ ├── types.ts
│ ├── utils.ts
│ └── version.ts
└── static
├── hotreloading.gif
└── svelte-logo.svg
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | compiler/example/App.js
3 | tests/
4 | App/
5 | Ssg/
6 | test.ts
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Crew Dev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Snel 🦕
2 |
3 |
4 |
5 |
A Cybernetical tool for svelte applications on deno in deno (Snel = fast in Nederlands)
25 |
26 | ## What is Snel?
27 |
28 | It is a `tool/framework` to compile .svelte component to javascript files to create web application using deno, vite and svelte
29 |
30 | ## Main features
31 |
32 | - simple setup
33 | - quick compilation
34 | - hot reloading
35 | - [import maps](https://github.com/WICG/import-maps) support (WIP)
36 | - support for scss and less out of the box (WIP)
37 | - support for typescript
38 | - [SSG](docs/ssg.md) (WIP)
39 | - SSR (WIP)
40 |
41 | ## What do I need to start using Snel?
42 |
43 | the only thing you need is to run the installation command.
44 |
45 | ```console
46 | deno install -A -n snel https://deno.land/x/snel/install.ts
47 | ```
48 |
49 | ## how to create a project with Snel?
50 |
51 | after running the installation script you just have to run the create command:
52 |
53 | ```console
54 | snel create [project name]
55 | ```
56 |
57 | then you just have to enter the created project and start the development server
58 |
59 | ```console
60 | cd ./[project name]
61 |
62 | deno task start
63 | ```
64 |
65 | this starts your application on a development server in the port you entered in the configuration
66 |
67 | ## Using svelte core libraries
68 |
69 | to use svelte core libraries such as transition, store, motion etc. must be called using the following syntax:
70 |
71 | ```javascript
72 | import { cubicOut } from "svelte/easing";
73 | import { tweened } from "svelte/motion";
74 | import { onMount } from "svelte";
75 | ```
76 |
77 | `svelte` tells the compiler that svelte core resources are being accessed.
78 |
79 | ## Using import maps
80 |
81 | You can use import maps to reference the dependencies you use, to use import maps from bes have an `import_map.json` file with the following structure:
82 |
83 | ```json
84 | {
85 | "imports": {
86 | "[package name]": "[package url]"
87 | }
88 | }
89 | ```
90 |
91 | In order for the compiler to know that you are using import maps, you need to import the dependencies as follows:
92 |
93 | ```javascript
94 | import moment from "moment";
95 | import axios from "axios";
96 | ```
97 |
98 | > **note**: you can use import maps inside svelte components
99 |
100 | ## Snel config file
101 |
102 | snel uses a configuration file to define different things, like the development server port or add different plugins, this file can be named as `snel.config.js` or `snel.config.ts`.
103 |
104 | `example: snel.config.js`
105 |
106 | ```javascript
107 | export default {
108 | port: 3000, // development server port
109 | mode: "dom", // type project "dom" | "ssg"
110 | plugins: [], // plugins must be compatible with rollup deno
111 | extendsImportMap: [
112 | // extends import map using externas import maps
113 | "https://denopkg.com/crewdevio/Snel-carbon@main/components.map.json",
114 | ],
115 | };
116 | ```
117 |
118 | config options:
119 |
120 | - port (number): port number for development server
121 | - mode (string): type project "dom" | "ssg"
122 | - plugins (Plugin[ ]): plugins must be compatible with [rollup deno](https://deno.land/x/drollup)
123 | - extendsImportMap (string[ ]): extends from externas import maps
124 |
125 | if you want to use `snel.config.ts` you can import `snelConfig` interface to provide type checking:
126 |
127 | `example: snel.config.ts`
128 |
129 | ```typescript
130 | import type { snelConfig } from "https://deno.land/x/snel/mod.ts";
131 |
132 | export default {
133 | ...
134 | };
135 | ```
136 |
137 | ## Manage import maps dependencies using [trex](https://github.com/crewdevio/Trex)
138 |
139 | if you don't have an import map.json file you can create it using the `trex install` command, trex is mainly focused on handling dependencies for `deno` but this doesn't prevent you from being able to use it to handle your dependencies for `snel/svelte`. to install any dependency you just have to use the [custom command](https://github.com/crewdevio/Trex#adding-custom-packages) from trex:
140 |
141 | ```console
142 | trex --custom axios=https://cdn.skypack.dev/axios
143 | ```
144 |
145 | this will install axios and it will make it accessible in the import map file:
146 |
147 | ```json
148 | {
149 | "imports": {
150 | "axios": "https://cdn.skypack.dev/axios"
151 | }
152 | }
153 | ```
154 |
155 | > **note**: You should know that your dependencies must be compatible with [es modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) and with the browser, if you refer to some import maps package and it is not found by the compiler, it will not be transformed, so an error will appear in your browser.
156 |
157 | we recommend these sites for you to install your dependencies
158 |
159 | - [skypack.dev](https://www.skypack.dev/)
160 | - [esm.sh](https://esm.sh/)
161 | - [jsdelivr.com](https://www.jsdelivr.com/)
162 |
163 | ## Typescript, Sass and Less support
164 |
165 | snel supports typescript out the box, so you can import typescript files into `.svelte` components without specifying the use of typescript within the component.
166 |
167 | `App.svelte`
168 |
169 | ```html
170 |
173 |
174 |
PI is = {PI}
175 |
176 |
181 | ```
182 |
183 | `pi.ts`
184 |
185 | ```typescript
186 | export const PI: number = Math.PI;
187 | ```
188 |
189 | Something important to know is that if you are going to import from typescript files without specifying the use of typescript within the component, you can only import non-types elements, example:
190 |
191 | - types
192 | - interfaces
193 |
194 | in case you want to use the typescript inside the components, you just have to specify it in the `lang` attribute:
195 |
196 | ```html
197 |
209 | ```
210 |
211 | to import types and interfaces into components these must be specified using the following syntax:
212 |
213 | ```html
214 |
217 | ```
218 |
219 | and you should only import types using this syntax and not combine imports with other elements.
220 |
221 | ```html
222 |
230 | ```
231 |
232 | > **note**: typescript support within components is not stable and compilation errors in hot reloading may appear.
233 |
234 | in the same way you can use the syntax of sass and less inside the components to define the styles.
235 |
236 | ```html
237 |
240 |
241 |
242 |
243 |
246 | ```
247 |
248 | > **note**: for now importing external styles is not available for css, sass and less.
249 |
250 | ## Import components and files
251 |
252 | when you create a project with snel you will notice that the components are imported as follows:
253 |
254 | `example`
255 |
256 | ```javascript
257 | // App.svelte
258 | import Home from "@/components/Home.svelte";
259 | ```
260 |
261 | `@/` It is equivalent to `./`, Similarly, if you need to access any component or file that is inside the src folder, you can use the following syntax:
262 |
263 | `example`
264 |
265 | ```javascript
266 | // src/Users.ts
267 | export default class Users {
268 | ...
269 | }
270 | ```
271 |
272 | ```javascript
273 | // src/components/views/content/User.svelte
274 | import Users from "~/Users.ts";
275 | ```
276 |
277 | this would be equivalent to:
278 |
279 | ```javascript
280 | import Users from "../../../Users.ts";
281 | ```
282 |
283 | summary:
284 |
285 | - `@/`
286 | - equivalent to `./`
287 | - `~/`
288 | - equivalent to `[current work directory]/src/`
289 | - `$/`
290 | - equivalent to `[current work directory]/`
291 |
292 | this syntax can be used in javascript, typescript files and components.
293 |
294 | > **note**: you can change the behavior by rewriting the pattern inside the import_map.json file, although be careful when doing this.
295 |
296 | ## Deploy SPA app
297 |
298 | If you want to have a simple workflow to deploy your SPA application, you can use this.
299 |
300 | `deploy`
301 |
302 | ```yml
303 | name: Build and Deploy
304 | on:
305 | push:
306 | branches:
307 | - main
308 | jobs:
309 | build:
310 | runs-on: windows-latest
311 | steps:
312 | - name: Checkout 🛎️
313 | uses: actions/checkout@v2.3.1
314 |
315 | - name: Install Deno
316 | uses: denolib/setup-deno@v2
317 | with:
318 | deno-version: v1.x
319 |
320 | - name: Build
321 | run: |
322 | deno run --allow-run --allow-read https://deno.land/x/snel/install.ts
323 | trex run build
324 | - name: Upload Artifacts 🔺
325 | uses: actions/upload-artifact@v1
326 | with:
327 | name: site
328 | path: dist
329 |
330 | deploy:
331 | needs: [build]
332 | runs-on: ubuntu-latest
333 | steps:
334 | - name: Checkout 🛎️
335 | uses: actions/checkout@v2.3.1
336 |
337 | - name: Download Artifacts 🔻
338 | uses: actions/download-artifact@v1
339 | with:
340 | name: site
341 |
342 | - name: Deploy 🚀
343 | uses: JamesIves/github-pages-deploy-action@4.1.4
344 | with:
345 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
346 | branch: deploy
347 | folder: "site"
348 | clean-exclude: |
349 | vercel.json
350 | manifest.json
351 | ```
352 |
353 | this compiles the application every time it is pushed to the `main` branch, and uploads the compiled files to the `deploy` branch, which could be deployed in hosts such as `vercel` or `netlify`.
354 |
355 | If you are using the snel client router and you are going to deploy vercel or netlify you must add the respective configuration files to avoid having 404 errors.
356 |
357 | `for vercel: vercel.json`
358 |
359 | ```json
360 | {
361 | "routes": [
362 | { "handle": "filesystem" },
363 | { "src": "/.*", "dest": "/index.html" }
364 | ]
365 | }
366 | ```
367 |
368 | `for netlify: _redirects`
369 |
370 | ```console
371 | /* /index.html 200
372 | ```
373 |
374 | to avoid this files was removed in each deploy, you can ignore specific files:
375 |
376 | ```yml
377 | ....
378 | - name: Deploy 🚀
379 | uses: JamesIves/github-pages-deploy-action@4.1.4
380 | with:
381 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
382 | branch: deploy
383 | folder: "site"
384 | clean-exclude: |
385 | vercel.json # <- ignore vercel.json and manifest.json file
386 | manifest.json
387 | ```
388 |
389 | for github pages you can use this trick:
390 |
391 | create a `404.html` file:
392 |
393 | ```html
394 |
395 |
396 |
397 |
398 | ....
399 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 | ```
411 |
412 | and in your `index.html` add this:
413 |
414 | ```html
415 |
416 |
417 |
418 |
419 | ....
420 |
425 |
426 |
427 | .....
428 |
448 |
449 |
450 | ```
451 |
452 | ## Hot Reloading
453 |
454 | Snel provides hot reload capability, it compiles and updates the application when changes are applied to it
455 |
456 | `example`
457 |
458 | 
459 |
--------------------------------------------------------------------------------
/cli.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Crew Dev.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | *
7 | */
8 |
9 | import { CommandNotFound, HelpCommand } from "./src/shared/log.ts";
10 | import { VERSION as cliVersion } from "./src/shared/version.ts";
11 | import { flags, keyWords } from "./src/shared/utils.ts";
12 | import { CreateProject } from "./src/cli/create.ts";
13 | import { PromptConfig } from "./src/cli/prompt.ts";
14 | import { showHelp } from "./src/shared/utils.ts";
15 | import { colors } from "./imports/fmt.ts";
16 |
17 | const { args: Args } = Deno;
18 | type Command = "create";
19 | const command = Args[0] as Command;
20 |
21 | const instructs = {
22 | // create a template project
23 | async create() {
24 | if (flags.help.includes(Args[1])) {
25 | return HelpCommand({
26 | command: {
27 | alias: [keyWords.create],
28 | description: "create a template project",
29 | },
30 | flags: [{ alias: flags.help, description: "show command help" }],
31 | });
32 | } else await CreateProject({ ...PromptConfig(), projectName: Args[1] });
33 | },
34 | };
35 |
36 | async function Main() {
37 | try {
38 | // execute instructions
39 | if (command === "create") {
40 | return await instructs.create();
41 | }
42 |
43 | // show version
44 | else if (flags.version.includes(Args[0])) {
45 | console.log(
46 | colors.green(
47 | `snel: ${colors.yellow(cliVersion)}\ndeno: ${colors.yellow(
48 | Deno.version.deno
49 | )}`
50 | )
51 | );
52 | }
53 | // show help
54 | else if (flags.help.includes(Args[0]) || !Args[0]) {
55 | showHelp();
56 | } else {
57 | CommandNotFound({
58 | commands: [keyWords.create],
59 | flags: [...flags.help, ...flags.version],
60 | });
61 | }
62 | } catch (error: any) {
63 | if (!(error instanceof Deno.errors.NotFound)) {
64 | console.log(error);
65 | }
66 | }
67 | }
68 |
69 | if (import.meta.main) {
70 | await Main();
71 | }
72 |
--------------------------------------------------------------------------------
/imports/fmt.ts:
--------------------------------------------------------------------------------
1 | export * as colors from "https://deno.land/std@0.213.0/fmt/colors.ts";
2 |
--------------------------------------------------------------------------------
/imports/fs.ts:
--------------------------------------------------------------------------------
1 | export * from "https://deno.land/std@0.213.0/fs/mod.ts";
2 |
--------------------------------------------------------------------------------
/imports/path.ts:
--------------------------------------------------------------------------------
1 | export * from "https://deno.land/std@0.213.0/path/mod.ts";
2 |
--------------------------------------------------------------------------------
/src/cli/create.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Crew Dev.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | *
7 | */
8 |
9 | import {
10 | globalCss,
11 | indexHtml,
12 | rootSvelte,
13 | Home,
14 | mainjs,
15 | SVG,
16 | DTS,
17 | JSCONFIg,
18 | VITE,
19 | DENO,
20 | SVELTE_CONFIG,
21 | gitIgnore,
22 | } from "./templates.ts";
23 | import type { CreateProjectOptions } from "../shared/types.ts";
24 | import { createDir, createFile } from "./io.ts";
25 | import { colors } from "../../imports/fmt.ts";
26 | import { join } from "../../imports/path.ts";
27 |
28 | export async function CreateProject(options: CreateProjectOptions) {
29 | const { projectName, port } = options;
30 |
31 | const startTime = Date.now();
32 | const projectRoot = `${Deno.cwd()}/${projectName}`;
33 |
34 | const builder = {
35 | domFiles: [
36 | {
37 | name: "index.html",
38 | path: projectRoot,
39 | source: indexHtml(),
40 | },
41 | {
42 | name: "app.css",
43 | path: `${projectRoot}/src/`,
44 | source: globalCss,
45 | },
46 | {
47 | name: "vite-env.d.ts",
48 | path: `${projectRoot}/src/`,
49 | source: DTS,
50 | },
51 | {
52 | name: "jsconfig.json",
53 | path: projectRoot,
54 | source: JSCONFIg,
55 | },
56 | {
57 | name: "App.svelte",
58 | path: `${projectRoot}/src/`,
59 | source: rootSvelte,
60 | },
61 | {
62 | name: "Counter.svelte",
63 | path: `${projectRoot}/src/components`,
64 | source: Home,
65 | },
66 | {
67 | name: "main.ts",
68 | path: `${projectRoot}/src/`,
69 | source: mainjs(),
70 | },
71 | {
72 | name: "vite.config.mts",
73 | path: projectRoot,
74 | source: VITE(port),
75 | },
76 | {
77 | name: "deno.json",
78 | path: projectRoot,
79 | source: DENO,
80 | },
81 | {
82 | name: "svelte.config.js",
83 | path: projectRoot,
84 | source: SVELTE_CONFIG,
85 | },
86 | {
87 | name: "svelte.svg",
88 | path: `${projectRoot}/src/assets/`,
89 | source: SVG,
90 | },
91 | {
92 | name: ".gitignore",
93 | path: projectRoot,
94 | source: gitIgnore,
95 | },
96 | ],
97 | domDir: [
98 | {
99 | name: "public",
100 | path: `${Deno.cwd()}/${projectName}`,
101 | },
102 | {
103 | name: projectName,
104 | path: Deno.cwd(),
105 | },
106 | {
107 | name: "src",
108 | path: `${Deno.cwd()}/${projectName}`,
109 | },
110 | {
111 | name: "components",
112 | path: `${Deno.cwd()}/${projectName}/src`,
113 | },
114 | {
115 | name: "assets",
116 | path: `${Deno.cwd()}/${projectName}/src`,
117 | },
118 | ],
119 | files() {
120 | return [...this.domFiles];
121 | },
122 | dirs() {
123 | return [...this.domDir];
124 | },
125 | };
126 |
127 | for (const dir of builder.dirs()) {
128 | const { name, path } = dir;
129 | await createDir(name, path);
130 | }
131 |
132 | for (const file of builder.files()) {
133 | const { name, path, source } = file;
134 | await createFile(name, path, source as string);
135 | }
136 |
137 | const endTime = Date.now();
138 |
139 | console.clear();
140 | console.log(`
141 | Done in ${(endTime - startTime) / 1000}s.
142 |
143 | Success! Created ${projectName} at ${join(Deno.cwd(), projectName)}
144 | Inside that directory, you can run several commands:
145 |
146 | ${colors.blue("deno task dev")} (HMR)
147 | Starts the development server.
148 |
149 | ${colors.blue("deno task build")}
150 | Bundles the app into static files for production.
151 |
152 | ${colors.blue("deno task preview")}
153 | Compile the project in preview mode.
154 |
155 | We suggest that you begin by typing:
156 |
157 | ${colors.blue("cd")} ${projectName}
158 | ${colors.blue("deno task dev")}
159 | `);
160 | }
161 |
--------------------------------------------------------------------------------
/src/cli/io.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Crew Dev.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | *
7 | */
8 |
9 | import { join } from "../../imports/path.ts";
10 |
11 | export async function createFile(name: string, path: string, source: string) {
12 | try {
13 | const file = await Deno.create(join(path, name));
14 | const encoder = new TextEncoder();
15 |
16 | await file.write(encoder.encode(source));
17 |
18 | return true;
19 | } catch (error: unknown) {
20 | console.log(error);
21 | }
22 | }
23 |
24 | export async function createDir(name: string, path: string) {
25 | try {
26 | await Deno.mkdir(join(path, name));
27 |
28 | return true;
29 | } catch (error: unknown) {
30 | console.log(error);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/cli/prompt.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Crew Dev.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | *
7 | */
8 |
9 | import type { CreateProjectOptions } from "../shared/types.ts";
10 | import { colors } from "../../imports/fmt.ts";
11 |
12 | const isNumber = (n: string) => parseInt(n);
13 |
14 | function validate(
15 | fields: string[],
16 | field: string,
17 | question: string,
18 | type: "number" | "string"
19 | ): string | number {
20 | if (type === "number" && isNumber(field)) return parseInt(field);
21 | else if (fields.includes(field)) return field.trim().toLowerCase();
22 | else {
23 | console.log(
24 | type === "string"
25 | ? colors.red(
26 | `\nthis field is no valid, these are valid "${fields.join(", ")}"\n`
27 | )
28 | : colors.red("\nis not a valid number\n")
29 | );
30 |
31 | return validate(fields, prompt(colors.green(question))!, question, type);
32 | }
33 | }
34 |
35 | export function PromptConfig(
36 | count = 0
37 | ): Omit {
38 | const answers: { [key: string]: string | number } = {};
39 |
40 | const questions = [
41 | {
42 | name: "port",
43 | message: "which port do you want the development server to run on?",
44 | _default: "3000",
45 | },
46 | ];
47 |
48 | for (const { message, name, _default } of questions) {
49 | switch (name) {
50 | case "port":
51 | answers[name] = validate(
52 | [],
53 | prompt(colors.green(message), _default)!,
54 | message,
55 | "number"
56 | );
57 | break;
58 | }
59 | }
60 |
61 | for (const answer in answers)
62 | console.log(colors.green(`\n${answer}: ${answers[answer]}`));
63 |
64 | const accept = confirm(colors.yellow("\nthis is the final configuration"));
65 |
66 | if (accept) return answers as Omit;
67 |
68 | return count <= 1 ? PromptConfig(count + 1) : Deno.exit(0);
69 | }
70 |
71 | export function notFoundConfig() {
72 | throw new Error(
73 | colors.red(`${colors.yellow("snel config")} file could not be found`)
74 | ).message;
75 | }
76 |
77 | export function serverLog({ dirName, port, localNet }: any) {
78 | console.clear();
79 | console.log(`
80 | ${colors.green("Compiled successfully!")}
81 |
82 | You can now view ${colors.bold(colors.yellow(dirName))} in the browser.
83 |
84 | ${colors.bold("Local:")} http://localhost:${colors.bold(
85 | port.toString()
86 | )}
87 | ${localNet}
88 |
89 | Note that the development build is not optimized.
90 | To create a production build, use ${colors.bold(
91 | colors.blue("trex run build")
92 | )}.
93 | `);
94 | }
95 |
--------------------------------------------------------------------------------
/src/cli/templates.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Crew Dev.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | *
7 | */
8 |
9 | export const indexHtml = () => `
10 |
11 |
12 |
13 |
14 |
15 |
16 | Vite + Deno + Svelte
17 |
18 |
19 |
20 |
21 |
22 | `;
23 |
24 | export const globalCss = `:root {
25 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
26 | font-size: 16px;
27 | line-height: 24px;
28 | font-weight: 400;
29 |
30 | color-scheme: light dark;
31 | color: rgba(255, 255, 255, 0.87);
32 | background-color: #242424;
33 |
34 | font-synthesis: none;
35 | text-rendering: optimizeLegibility;
36 | -webkit-font-smoothing: antialiased;
37 | -moz-osx-font-smoothing: grayscale;
38 | -webkit-text-size-adjust: 100%;
39 | }
40 |
41 | a {
42 | font-weight: 500;
43 | color: #646cff;
44 | text-decoration: inherit;
45 | }
46 | a:hover {
47 | color: #535bf2;
48 | }
49 |
50 | body {
51 | margin: 0;
52 | display: flex;
53 | place-items: center;
54 | min-width: 320px;
55 | min-height: 100vh;
56 | }
57 |
58 | h1 {
59 | font-size: 3.2em;
60 | line-height: 1.1;
61 | }
62 |
63 | .card {
64 | padding: 2em;
65 | }
66 |
67 | #app {
68 | max-width: 1280px;
69 | margin: 0 auto;
70 | padding: 2rem;
71 | text-align: center;
72 | }
73 |
74 | button {
75 | border-radius: 8px;
76 | border: 1px solid transparent;
77 | padding: 0.6em 1.2em;
78 | font-size: 1em;
79 | font-weight: 500;
80 | font-family: inherit;
81 | background-color: #1a1a1a;
82 | cursor: pointer;
83 | transition: border-color 0.25s;
84 | }
85 | button:hover {
86 | border-color: #646cff;
87 | }
88 | button:focus,
89 | button:focus-visible {
90 | outline: 4px auto -webkit-focus-ring-color;
91 | }
92 |
93 | @media (prefers-color-scheme: light) {
94 | :root {
95 | color: #213547;
96 | background-color: #ffffff;
97 | }
98 | a:hover {
99 | color: #747bff;
100 | }
101 | button {
102 | background-color: #f9f9f9;
103 | }
104 | }
105 | `;
106 |
107 | export const rootSvelte = `
111 |
112 |
113 |