sv 0.5.0 → 0.5.2
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 +2 -17
- package/dist/bin.js +44685 -1969
- package/dist/bin.js.map +1 -1
- package/dist/{index-CfDBZLMZ.js → index-A89HFWzv.js} +3 -3
- package/dist/index-A89HFWzv.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shared.json +14 -14
- package/dist/templates/demo/files.types=checkjs.json +8 -8
- package/dist/templates/demo/files.types=none.json +7 -7
- package/dist/templates/demo/files.types=typescript.json +8 -8
- package/dist/templates/demo/meta.json +2 -2
- package/dist/templates/demo/package.json +2 -2
- package/dist/templates/{skeletonlib → library}/files.types=checkjs.json +2 -2
- package/dist/templates/{skeletonlib → library}/files.types=none.json +1 -1
- package/dist/templates/{skeletonlib → library}/files.types=typescript.json +2 -2
- package/dist/templates/library/meta.json +4 -0
- package/dist/templates/{skeletonlib → library}/package.json +6 -5
- package/dist/templates/{skeleton → minimal}/files.types=checkjs.json +2 -2
- package/dist/templates/{skeleton → minimal}/files.types=none.json +1 -1
- package/dist/templates/{skeleton → minimal}/files.types=typescript.json +2 -2
- package/dist/templates/minimal/meta.json +4 -0
- package/dist/templates/{skeleton → minimal}/package.json +2 -3
- package/dist/unocss-BUQS5wKg.js +6 -0
- package/dist/unocss-BUQS5wKg.js.map +1 -0
- package/dist/unplugin-icons-BietOpsP.js +6 -0
- package/dist/unplugin-icons-BietOpsP.js.map +1 -0
- package/package.json +19 -19
- package/dist/index-CfDBZLMZ.js.map +0 -1
- package/dist/templates/skeleton/meta.json +0 -4
- package/dist/templates/skeletonlib/meta.json +0 -4
- package/dist/unocss-Dk7i15rK.js +0 -11
- package/dist/unocss-Dk7i15rK.js.map +0 -1
- package/dist/unplugin-icons-DkNLYvBs.js +0 -11
- package/dist/unplugin-icons-DkNLYvBs.js.map +0 -1
- /package/dist/templates/{skeletonlib → library}/assets/DOT-gitignore +0 -0
- /package/dist/templates/{skeleton → library}/assets/DOT-npmrc +0 -0
- /package/dist/templates/{skeletonlib → library}/assets/src/app.html +0 -0
- /package/dist/templates/{skeleton → library}/assets/static/favicon.png +0 -0
- /package/dist/templates/{skeleton → minimal}/assets/DOT-gitignore +0 -0
- /package/dist/templates/{skeletonlib → minimal}/assets/DOT-npmrc +0 -0
- /package/dist/templates/{skeleton → minimal}/assets/src/app.html +0 -0
- /package/dist/templates/{skeletonlib → minimal}/assets/static/favicon.png +0 -0
|
@@ -32,7 +32,7 @@ function dist(path2) {
|
|
|
32
32
|
new URL(`./${!insideDistFolder ? "dist/" : ""}${path2}`, import.meta.url).href
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
|
-
const templateTypes = ["
|
|
35
|
+
const templateTypes = ["minimal", "demo", "library"];
|
|
36
36
|
function create(cwd, options) {
|
|
37
37
|
mkdirp(cwd);
|
|
38
38
|
write_template_files(options.template, options.types, options.name, cwd);
|
|
@@ -86,7 +86,7 @@ function write_common_files(cwd, options, name) {
|
|
|
86
86
|
fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, " ") + "\n");
|
|
87
87
|
}
|
|
88
88
|
function matches_condition(condition, options) {
|
|
89
|
-
if (condition === "demo" || condition === "
|
|
89
|
+
if (condition === "demo" || condition === "minimal" || condition === "library") {
|
|
90
90
|
return options.template === condition;
|
|
91
91
|
}
|
|
92
92
|
if (condition === "typescript" || condition === "checkjs") {
|
|
@@ -134,4 +134,4 @@ function to_valid_package_name(name) {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
export { create as c, templates as t };
|
|
137
|
-
//# sourceMappingURL=index-
|
|
137
|
+
//# sourceMappingURL=index-A89HFWzv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-A89HFWzv.js","sources":["../../create/dist/index.js"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nfunction mkdirp(dir) {\n try {\n fs.mkdirSync(dir, { recursive: true });\n } catch (err) {\n const e = err;\n if (e.code === \"EEXIST\") return;\n throw e;\n }\n}\nfunction identity(x) {\n return x;\n}\nfunction copy(from, to, rename = identity) {\n if (!fs.existsSync(from)) return;\n const stats = fs.statSync(from);\n if (stats.isDirectory()) {\n fs.readdirSync(from).forEach((file) => {\n copy(path.join(from, file), path.join(to, rename(file)));\n });\n } else {\n mkdirp(path.dirname(to));\n fs.copyFileSync(from, to);\n }\n}\nfunction dist(path2) {\n const insideDistFolder = import.meta.url.includes(\"dist\");\n return fileURLToPath(\n new URL(`./${!insideDistFolder ? \"dist/\" : \"\"}${path2}`, import.meta.url).href\n );\n}\n\nconst templateTypes = [\"minimal\", \"demo\", \"library\"];\nfunction create(cwd, options) {\n mkdirp(cwd);\n write_template_files(options.template, options.types, options.name, cwd);\n write_common_files(cwd, options, options.name);\n}\nconst templates = templateTypes.map((dir) => {\n const meta_file = dist(`templates/${dir}/meta.json`);\n const { title, description } = JSON.parse(fs.readFileSync(meta_file, \"utf8\"));\n return {\n name: dir,\n title,\n description\n };\n});\nfunction write_template_files(template, types, name, cwd) {\n const dir = dist(`templates/${template}`);\n copy(`${dir}/assets`, cwd, (name2) => name2.replace(\"DOT-\", \".\"));\n copy(`${dir}/package.json`, `${cwd}/package.json`);\n const manifest = `${dir}/files.types=${types}.json`;\n const files = JSON.parse(fs.readFileSync(manifest, \"utf-8\"));\n files.forEach((file) => {\n const dest = path.join(cwd, file.name);\n mkdirp(path.dirname(dest));\n fs.writeFileSync(dest, file.contents.replace(/~TODO~/g, name));\n });\n}\nfunction write_common_files(cwd, options, name) {\n const shared = dist(\"shared.json\");\n const { files } = JSON.parse(fs.readFileSync(shared, \"utf-8\"));\n const pkg_file = path.join(cwd, \"package.json\");\n const pkg = (\n /** @type {any} */\n JSON.parse(fs.readFileSync(pkg_file, \"utf-8\"))\n );\n sort_files(files).forEach((file) => {\n const include = file.include.every((condition) => matches_condition(condition, options));\n const exclude = file.exclude.some((condition) => matches_condition(condition, options));\n if (exclude || !include) return;\n if (file.name === \"package.json\") {\n const new_pkg = JSON.parse(file.contents);\n merge(pkg, new_pkg);\n } else {\n const dest = path.join(cwd, file.name);\n mkdirp(path.dirname(dest));\n fs.writeFileSync(dest, file.contents);\n }\n });\n pkg.dependencies = sort_keys(pkg.dependencies);\n pkg.devDependencies = sort_keys(pkg.devDependencies);\n pkg.name = to_valid_package_name(name);\n fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, \"\t\") + \"\\n\");\n}\nfunction matches_condition(condition, options) {\n if (condition === \"demo\" || condition === \"minimal\" || condition === \"library\") {\n return options.template === condition;\n }\n if (condition === \"typescript\" || condition === \"checkjs\") {\n return options.types === condition;\n }\n return !!options[condition];\n}\nfunction merge(target, source) {\n for (const key in source) {\n if (key in target) {\n const target_value = target[key];\n const source_value = source[key];\n if (typeof source_value !== typeof target_value || Array.isArray(source_value) !== Array.isArray(target_value)) {\n throw new Error(\"Mismatched values\");\n }\n if (typeof source_value === \"object\") {\n merge(target_value, source_value);\n } else {\n target[key] = source_value;\n }\n } else {\n target[key] = source[key];\n }\n }\n}\nfunction sort_keys(obj) {\n if (!obj) return;\n const sorted = {};\n Object.keys(obj).sort().forEach((key) => {\n sorted[key] = obj[key];\n });\n return sorted;\n}\nfunction sort_files(files) {\n return files.sort((f1, f2) => {\n const f1_more_generic = f1.include.every((include) => f2.include.includes(include)) && f1.exclude.every((exclude) => f2.exclude.includes(exclude));\n const f2_more_generic = f2.include.every((include) => f1.include.includes(include)) && f2.exclude.every((exclude) => f1.exclude.includes(exclude));\n const same = f1_more_generic && f2_more_generic;\n const different = !f1_more_generic && !f2_more_generic;\n return same || different ? 0 : f1_more_generic ? -1 : 1;\n });\n}\nfunction to_valid_package_name(name) {\n return name.trim().toLowerCase().replace(/\\s+/g, \"-\").replace(/^[._]/, \"\").replace(/[^a-z0-9~.-]+/g, \"-\");\n}\n\nexport { create, templates };\n//# sourceMappingURL=index.js.map\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { create } from '@
|
|
1
|
+
import { create } from '@sveltejs/create';
|
|
2
2
|
export { create };
|
package/dist/index.js
CHANGED
package/dist/shared.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"name": "README.md",
|
|
5
5
|
"include": [],
|
|
6
6
|
"exclude": [],
|
|
7
|
-
"contents": "# create-svelte\n\nEverything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).\n\n## Creating a project\n\nIf you're seeing this, you've probably already done this step. Congrats!\n\n```bash\n# create a new project in the current directory\nnpx sv create\n\n# create a new project in my-app\nnpx sv create my-app\n```\n\n## Developing\n\nOnce you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:\n\n```bash\nnpm run dev\n\n# or start the server and open the app in a new browser tab\nnpm run dev -- --open\n```\n\n## Building\n\nTo create a production version of your app:\n\n```bash\nnpm run build\n```\n\nYou can preview the production build with `npm run preview`.\n\n> To deploy your app, you may need to install an [adapter](https://
|
|
7
|
+
"contents": "# create-svelte\n\nEverything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).\n\n## Creating a project\n\nIf you're seeing this, you've probably already done this step. Congrats!\n\n```bash\n# create a new project in the current directory\nnpx sv create\n\n# create a new project in my-app\nnpx sv create my-app\n```\n\n## Developing\n\nOnce you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:\n\n```bash\nnpm run dev\n\n# or start the server and open the app in a new browser tab\nnpm run dev -- --open\n```\n\n## Building\n\nTo create a production version of your app:\n\n```bash\nnpm run build\n```\n\nYou can preview the production build with `npm run preview`.\n\n> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.\n"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"name": "jsconfig.json",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"checkjs"
|
|
13
13
|
],
|
|
14
14
|
"exclude": [],
|
|
15
|
-
"contents": "{\n\t\"extends\": \"./.svelte-kit/tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"resolveJsonModule\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"sourceMap\": true,\n\t\t\"strict\": true,\n\t\t\"moduleResolution\": \"bundler\"\n\t}\n\t// Path aliases are handled by https://
|
|
15
|
+
"contents": "{\n\t\"extends\": \"./.svelte-kit/tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"resolveJsonModule\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"sourceMap\": true,\n\t\t\"strict\": true,\n\t\t\"moduleResolution\": \"bundler\"\n\t}\n\t// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias\n\t// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files\n\t//\n\t// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes\n\t// from the referenced tsconfig.json - TypeScript does not merge them in\n}\n"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"name": "package.json",
|
|
@@ -20,15 +20,15 @@
|
|
|
20
20
|
"checkjs"
|
|
21
21
|
],
|
|
22
22
|
"exclude": [],
|
|
23
|
-
"contents": "{\n\t\"scripts\": {\n\t\t\"check\": \"svelte-kit sync && svelte-check --tsconfig ./jsconfig.json\",\n\t\t\"check:watch\": \"svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch\"\n\t},\n\t\"devDependencies\": {\n\t\t\"
|
|
23
|
+
"contents": "{\n\t\"scripts\": {\n\t\t\"check\": \"svelte-kit sync && svelte-check --tsconfig ./jsconfig.json\",\n\t\t\"check:watch\": \"svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch\"\n\t},\n\t\"devDependencies\": {\n\t\t\"svelte-check\": \"^4.0.0\",\n\t\t\"typescript\": \"^5.0.0\"\n\t}\n}\n"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"name": "README.md",
|
|
27
27
|
"include": [
|
|
28
|
-
"
|
|
28
|
+
"library"
|
|
29
29
|
],
|
|
30
30
|
"exclude": [],
|
|
31
|
-
"contents": "# create-svelte\n\nEverything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).\n\nRead more about creating a library [in the docs](https://
|
|
31
|
+
"contents": "# create-svelte\n\nEverything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).\n\nRead more about creating a library [in the docs](https://svelte.dev/docs/kit/packaging).\n\n## Creating a project\n\nIf you're seeing this, you've probably already done this step. Congrats!\n\n```bash\n# create a new project in the current directory\nnpx sv create\n\n# create a new project in my-app\nnpx sv create my-app\n```\n\n## Developing\n\nOnce you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:\n\n```bash\nnpm run dev\n\n# or start the server and open the app in a new browser tab\nnpm run dev -- --open\n```\n\nEverything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.\n\n## Building\n\nTo build your library:\n\n```bash\nnpm run package\n```\n\nTo create a production version of your showcase app:\n\n```bash\nnpm run build\n```\n\nYou can preview the production build with `npm run preview`.\n\n> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.\n\n## Publishing\n\nGo into the `package.json` and give your package the desired name through the `\"name\"` option. Also consider adding a `\"license\"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).\n\nTo publish your library to [npm](https://www.npmjs.com):\n\n```bash\nnpm publish\n```\n"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"name": "package.json",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"typescript"
|
|
37
37
|
],
|
|
38
38
|
"exclude": [],
|
|
39
|
-
"contents": "{\n\t\"scripts\": {\n\t\t\"check\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json\",\n\t\t\"check:watch\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch\"\n\t},\n\t\"devDependencies\": {\n\t\t\"
|
|
39
|
+
"contents": "{\n\t\"scripts\": {\n\t\t\"check\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json\",\n\t\t\"check:watch\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch\"\n\t},\n\t\"devDependencies\": {\n\t\t\"svelte-check\": \"^4.0.0\",\n\t\t\"typescript\": \"^5.0.0\"\n\t}\n}\n"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"name": "svelte.config.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"typescript"
|
|
45
45
|
],
|
|
46
46
|
"exclude": [],
|
|
47
|
-
"contents": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://
|
|
47
|
+
"contents": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://svelte.dev/docs/kit/integrations#preprocessors\n\t// for more information about preprocessors\n\tpreprocess: vitePreprocess(),\n\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"name": "tsconfig.json",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"typescript"
|
|
53
53
|
],
|
|
54
54
|
"exclude": [],
|
|
55
|
-
"contents": "{\n\t\"extends\": \"./.svelte-kit/tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"resolveJsonModule\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"sourceMap\": true,\n\t\t\"strict\": true,\n\t\t\"moduleResolution\": \"bundler\"\n\t}\n\t// Path aliases are handled by https://
|
|
55
|
+
"contents": "{\n\t\"extends\": \"./.svelte-kit/tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"resolveJsonModule\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"sourceMap\": true,\n\t\t\"strict\": true,\n\t\t\"moduleResolution\": \"bundler\"\n\t}\n\t// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias\n\t// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files\n\t//\n\t// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes\n\t// from the referenced tsconfig.json - TypeScript does not merge them in\n}\n"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"name": "svelte.config.js",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"exclude": [
|
|
61
61
|
"typescript"
|
|
62
62
|
],
|
|
63
|
-
"contents": "import adapter from '@sveltejs/adapter-auto';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://
|
|
63
|
+
"contents": "import adapter from '@sveltejs/adapter-auto';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"name": "vite.config.ts",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"checkjs"
|
|
86
86
|
],
|
|
87
87
|
"exclude": [],
|
|
88
|
-
"contents": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://
|
|
88
|
+
"contents": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://svelte.dev/docs/kit/integrations#preprocessors\n\t// for more information about preprocessors\n\tpreprocess: vitePreprocess(),\n\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
"name": "svelte.config.js",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"typescript"
|
|
95
95
|
],
|
|
96
96
|
"exclude": [],
|
|
97
|
-
"contents": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://
|
|
97
|
+
"contents": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://svelte.dev/docs/kit/integrations#preprocessors\n\t// for more information about preprocessors\n\tpreprocess: vitePreprocess(),\n\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "svelte.config.js",
|
|
@@ -104,12 +104,12 @@
|
|
|
104
104
|
"exclude": [
|
|
105
105
|
"typescript"
|
|
106
106
|
],
|
|
107
|
-
"contents": "import adapter from '@sveltejs/adapter-auto';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://
|
|
107
|
+
"contents": "import adapter from '@sveltejs/adapter-auto';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.\n\t\t// If your environment is not supported, or you settled on a specific environment, switch out the adapter.\n\t\t// See https://svelte.dev/docs/kit/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
|
|
108
108
|
},
|
|
109
109
|
{
|
|
110
110
|
"name": "tsconfig.json",
|
|
111
111
|
"include": [
|
|
112
|
-
"
|
|
112
|
+
"library",
|
|
113
113
|
"typescript"
|
|
114
114
|
],
|
|
115
115
|
"exclude": [],
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
{
|
|
119
119
|
"name": "jsconfig.json",
|
|
120
120
|
"include": [
|
|
121
|
-
"
|
|
121
|
+
"library"
|
|
122
122
|
],
|
|
123
123
|
"exclude": [
|
|
124
124
|
"typescript"
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"name": "src/app.d.ts",
|
|
4
|
-
"contents": "// See https://
|
|
4
|
+
"contents": "// See https://svelte.dev/docs/kit/types#app\n// for information about these interfaces\ndeclare global {\n\tnamespace App {\n\t\t// interface Error {}\n\t\t// interface Locals {}\n\t\t// interface PageData {}\n\t\t// interface PageState {}\n\t\t// interface Platform {}\n\t}\n}\n\nexport {};\n"
|
|
5
5
|
},
|
|
6
6
|
{
|
|
7
7
|
"name": "src/routes/+layout.svelte",
|
|
8
|
-
"contents": "<script>\n\timport Header from './Header.svelte';\n\timport '../app.css';\n</script>\n\n<div class=\"app\">\n\t<Header />\n\n\t<main>\n\t\t
|
|
8
|
+
"contents": "<script>\n\timport Header from './Header.svelte';\n\timport '../app.css';\n\n\t/** @type {{children: import('svelte').Snippet}} */\n\tlet { children } = $props();\n</script>\n\n<div class=\"app\">\n\t<Header />\n\n\t<main>\n\t\t{@render children()}\n\t</main>\n\n\t<footer>\n\t\t<p>\n\t\t\tvisit <a href=\"https://svelte.dev/docs/kit\">svelte.dev/docs/kit</a> to learn about SvelteKit\n\t\t</p>\n\t</footer>\n</div>\n\n<style>\n\t.app {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tmin-height: 100vh;\n\t}\n\n\tmain {\n\t\tflex: 1;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tpadding: 1rem;\n\t\twidth: 100%;\n\t\tmax-width: 64rem;\n\t\tmargin: 0 auto;\n\t\tbox-sizing: border-box;\n\t}\n\n\tfooter {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tpadding: 12px;\n\t}\n\n\tfooter a {\n\t\tfont-weight: bold;\n\t}\n\n\t@media (min-width: 480px) {\n\t\tfooter {\n\t\t\tpadding: 12px 0;\n\t\t}\n\t}\n</style>\n"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"name": "src/routes/+page.svelte",
|
|
12
|
-
"contents": "<script>\n\timport Counter from './Counter.svelte';\n\timport welcome from '$lib/images/svelte-welcome.webp';\n\timport
|
|
12
|
+
"contents": "<script>\n\timport Counter from './Counter.svelte';\n\timport welcome from '$lib/images/svelte-welcome.webp';\n\timport welcomeFallback from '$lib/images/svelte-welcome.png';\n</script>\n\n<svelte:head>\n\t<title>Home</title>\n\t<meta name=\"description\" content=\"Svelte demo app\" />\n</svelte:head>\n\n<section>\n\t<h1>\n\t\t<span class=\"welcome\">\n\t\t\t<picture>\n\t\t\t\t<source srcset={welcome} type=\"image/webp\" />\n\t\t\t\t<img src={welcomeFallback} alt=\"Welcome\" />\n\t\t\t</picture>\n\t\t</span>\n\n\t\tto your new<br />SvelteKit app\n\t</h1>\n\n\t<h2>\n\t\ttry editing <strong>src/routes/+page.svelte</strong>\n\t</h2>\n\n\t<Counter />\n</section>\n\n<style>\n\tsection {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tflex: 0.6;\n\t}\n\n\th1 {\n\t\twidth: 100%;\n\t}\n\n\t.welcome {\n\t\tdisplay: block;\n\t\tposition: relative;\n\t\twidth: 100%;\n\t\theight: 0;\n\t\tpadding: 0 0 calc(100% * 495 / 2048) 0;\n\t}\n\n\t.welcome img {\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\ttop: 0;\n\t\tdisplay: block;\n\t}\n</style>\n"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": "src/routes/+page.js",
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"name": "src/routes/Counter.svelte",
|
|
20
|
-
"contents": "<script>\n\timport { spring } from 'svelte/motion';\n\n\tlet count = 0;\n\n\tconst
|
|
20
|
+
"contents": "<script>\n\timport { spring } from 'svelte/motion';\n\n\tlet count = $state(0);\n\n\t// svelte-ignore state_referenced_locally\n\tconst displayedCount = spring(count);\n\n\t$effect(() => {\n\t\tdisplayedCount.set(count);\n\t});\n\tlet offset = $derived(modulo($displayedCount, 1));\n\n\t/**\n\t * @param {number} n\n\t * @param {number} m\n\t */\n\tfunction modulo(n, m) {\n\t\t// handle negative numbers\n\t\treturn ((n % m) + m) % m;\n\t}\n</script>\n\n<div class=\"counter\">\n\t<button onclick={() => (count -= 1)} aria-label=\"Decrease the counter by one\">\n\t\t<svg aria-hidden=\"true\" viewBox=\"0 0 1 1\">\n\t\t\t<path d=\"M0,0.5 L1,0.5\" />\n\t\t</svg>\n\t</button>\n\n\t<div class=\"counter-viewport\">\n\t\t<div class=\"counter-digits\" style=\"transform: translate(0, {100 * offset}%)\">\n\t\t\t<strong class=\"hidden\" aria-hidden=\"true\">{Math.floor($displayedCount + 1)}</strong>\n\t\t\t<strong>{Math.floor($displayedCount)}</strong>\n\t\t</div>\n\t</div>\n\n\t<button onclick={() => (count += 1)} aria-label=\"Increase the counter by one\">\n\t\t<svg aria-hidden=\"true\" viewBox=\"0 0 1 1\">\n\t\t\t<path d=\"M0,0.5 L1,0.5 M0.5,0 L0.5,1\" />\n\t\t</svg>\n\t</button>\n</div>\n\n<style>\n\t.counter {\n\t\tdisplay: flex;\n\t\tborder-top: 1px solid rgba(0, 0, 0, 0.1);\n\t\tborder-bottom: 1px solid rgba(0, 0, 0, 0.1);\n\t\tmargin: 1rem 0;\n\t}\n\n\t.counter button {\n\t\twidth: 2em;\n\t\tpadding: 0;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tborder: 0;\n\t\tbackground-color: transparent;\n\t\ttouch-action: manipulation;\n\t\tfont-size: 2rem;\n\t}\n\n\t.counter button:hover {\n\t\tbackground-color: var(--color-bg-1);\n\t}\n\n\tsvg {\n\t\twidth: 25%;\n\t\theight: 25%;\n\t}\n\n\tpath {\n\t\tvector-effect: non-scaling-stroke;\n\t\tstroke-width: 2px;\n\t\tstroke: #444;\n\t}\n\n\t.counter-viewport {\n\t\twidth: 8em;\n\t\theight: 4em;\n\t\toverflow: hidden;\n\t\ttext-align: center;\n\t\tposition: relative;\n\t}\n\n\t.counter-viewport strong {\n\t\tposition: absolute;\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tfont-weight: 400;\n\t\tcolor: var(--color-theme-1);\n\t\tfont-size: 4rem;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t}\n\n\t.counter-digits {\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t}\n\n\t.hidden {\n\t\ttop: -100%;\n\t\tuser-select: none;\n\t}\n</style>\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"name": "src/routes/Header.svelte",
|
|
24
|
-
"contents": "<script>\n\timport { page } from '$app/stores';\n\timport logo from '$lib/images/svelte-logo.svg';\n\timport github from '$lib/images/github.svg';\n</script>\n\n<header>\n\t<div class=\"corner\">\n\t\t<a href=\"https://
|
|
24
|
+
"contents": "<script>\n\timport { page } from '$app/stores';\n\timport logo from '$lib/images/svelte-logo.svg';\n\timport github from '$lib/images/github.svg';\n</script>\n\n<header>\n\t<div class=\"corner\">\n\t\t<a href=\"https://svelte.dev/docs/kit\">\n\t\t\t<img src={logo} alt=\"SvelteKit\" />\n\t\t</a>\n\t</div>\n\n\t<nav>\n\t\t<svg viewBox=\"0 0 2 3\" aria-hidden=\"true\">\n\t\t\t<path d=\"M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z\" />\n\t\t</svg>\n\t\t<ul>\n\t\t\t<li aria-current={$page.url.pathname === '/' ? 'page' : undefined}>\n\t\t\t\t<a href=\"/\">Home</a>\n\t\t\t</li>\n\t\t\t<li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>\n\t\t\t\t<a href=\"/about\">About</a>\n\t\t\t</li>\n\t\t\t<li aria-current={$page.url.pathname.startsWith('/sverdle') ? 'page' : undefined}>\n\t\t\t\t<a href=\"/sverdle\">Sverdle</a>\n\t\t\t</li>\n\t\t</ul>\n\t\t<svg viewBox=\"0 0 2 3\" aria-hidden=\"true\">\n\t\t\t<path d=\"M0,0 L0,3 C0.5,3 0.5,3 1,2 L2,0 Z\" />\n\t\t</svg>\n\t</nav>\n\n\t<div class=\"corner\">\n\t\t<a href=\"https://github.com/sveltejs/kit\">\n\t\t\t<img src={github} alt=\"GitHub\" />\n\t\t</a>\n\t</div>\n</header>\n\n<style>\n\theader {\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n\t}\n\n\t.corner {\n\t\twidth: 3em;\n\t\theight: 3em;\n\t}\n\n\t.corner a {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t}\n\n\t.corner img {\n\t\twidth: 2em;\n\t\theight: 2em;\n\t\tobject-fit: contain;\n\t}\n\n\tnav {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\t--background: rgba(255, 255, 255, 0.7);\n\t}\n\n\tsvg {\n\t\twidth: 2em;\n\t\theight: 3em;\n\t\tdisplay: block;\n\t}\n\n\tpath {\n\t\tfill: var(--background);\n\t}\n\n\tul {\n\t\tposition: relative;\n\t\tpadding: 0;\n\t\tmargin: 0;\n\t\theight: 3em;\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tlist-style: none;\n\t\tbackground: var(--background);\n\t\tbackground-size: contain;\n\t}\n\n\tli {\n\t\tposition: relative;\n\t\theight: 100%;\n\t}\n\n\tli[aria-current='page']::before {\n\t\t--size: 6px;\n\t\tcontent: '';\n\t\twidth: 0;\n\t\theight: 0;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: calc(50% - var(--size));\n\t\tborder: var(--size) solid transparent;\n\t\tborder-top: var(--size) solid var(--color-theme-1);\n\t}\n\n\tnav a {\n\t\tdisplay: flex;\n\t\theight: 100%;\n\t\talign-items: center;\n\t\tpadding: 0 0.5rem;\n\t\tcolor: var(--color-text);\n\t\tfont-weight: 700;\n\t\tfont-size: 0.8rem;\n\t\ttext-transform: uppercase;\n\t\tletter-spacing: 0.1em;\n\t\ttext-decoration: none;\n\t\ttransition: color 0.2s linear;\n\t}\n\n\ta:hover {\n\t\tcolor: var(--color-theme-1);\n\t}\n</style>\n"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"name": "src/routes/about/+page.svelte",
|
|
28
|
-
"contents": "<svelte:head>\n\t<title>About</title>\n\t<meta name=\"description\" content=\"About this app\" />\n</svelte:head>\n\n<div class=\"text-column\">\n\t<h1>About this app</h1>\n\n\t<p>\n\t\tThis is a <a href=\"https://
|
|
28
|
+
"contents": "<svelte:head>\n\t<title>About</title>\n\t<meta name=\"description\" content=\"About this app\" />\n</svelte:head>\n\n<div class=\"text-column\">\n\t<h1>About this app</h1>\n\n\t<p>\n\t\tThis is a <a href=\"https://svelte.dev/docs/kit\">SvelteKit</a> app. You can make your own by typing\n\t\tthe following into your command line and following the prompts:\n\t</p>\n\n\t<pre>npx sv create</pre>\n\n\t<p>\n\t\tThe page you're looking at is purely static HTML, with no client-side interactivity needed.\n\t\tBecause of that, we don't need to load any JavaScript. Try viewing the page's source, or opening\n\t\tthe devtools network panel and reloading.\n\t</p>\n\n\t<p>\n\t\tThe <a href=\"/sverdle\">Sverdle</a> page illustrates SvelteKit's data loading and form handling. Try\n\t\tusing it with JavaScript disabled!\n\t</p>\n</div>\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"name": "src/routes/about/+page.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"name": "src/routes/sverdle/+page.svelte",
|
|
40
|
-
"contents": "<script>\n\timport { confetti } from '@neoconfetti/svelte';\n\timport { enhance } from '$app/forms';\n\n\timport { reduced_motion } from './reduced-motion';\n\n\t/** @type {import('./$types').PageData} */\n\texport let data;\n\n\t/** @type {import('./$types').ActionData} */\n\texport let form;\n\n\t/** Whether or not the user has won */\n\t$: won = data.answers.at(-1) === 'xxxxx';\n\n\t/** The index of the current guess */\n\t$: i = won ? -1 : data.answers.length;\n\n\t/** The current guess */\n\t$: currentGuess = data.guesses[i] || '';\n\n\t/** Whether the current guess can be submitted */\n\t$: submittable = currentGuess.length === 5;\n\n\t/**\n\t * A map of classnames for all letters that have been guessed,\n\t * used for styling the keyboard\n\t * @type {Record<string, 'exact' | 'close' | 'missing'>}\n\t */\n\tlet classnames;\n\n\t/**\n\t * A map of descriptions for all letters that have been guessed,\n\t * used for adding text for assistive technology (e.g. screen readers)\n\t * @type {Record<string, string>}\n\t */\n\tlet description;\n\n\t$: {\n\t\tclassnames = {};\n\t\tdescription = {};\n\n\t\tdata.answers.forEach((answer, i) => {\n\t\t\tconst guess = data.guesses[i];\n\n\t\t\tfor (let i = 0; i < 5; i += 1) {\n\t\t\t\tconst letter = guess[i];\n\n\t\t\t\tif (answer[i] === 'x') {\n\t\t\t\t\tclassnames[letter] = 'exact';\n\t\t\t\t\tdescription[letter] = 'correct';\n\t\t\t\t} else if (!classnames[letter]) {\n\t\t\t\t\tclassnames[letter] = answer[i] === 'c' ? 'close' : 'missing';\n\t\t\t\t\tdescription[letter] = answer[i] === 'c' ? 'present' : 'absent';\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Modify the game state without making a trip to the server,\n\t * if client-side JavaScript is enabled\n\t * @param {MouseEvent} event\n\t */\n\tfunction update(event) {\n\t\tconst key = /** @type {HTMLButtonElement} */ (event.target).getAttribute('data-key');\n\n\t\tif (key === 'backspace') {\n\t\t\tcurrentGuess = currentGuess.slice(0, -1);\n\t\t\tif (form?.badGuess) form.badGuess = false;\n\t\t} else if (currentGuess.length < 5) {\n\t\t\tcurrentGuess += key;\n\t\t}\n\t}\n\n\t/**\n\t * Trigger form logic in response to a keydown event, so that\n\t * desktop users can use the keyboard to play the game\n\t * @param {KeyboardEvent} event\n\t */\n\tfunction keydown(event) {\n\t\tif (event.metaKey) return;\n\n\t\tif (event.key === 'Enter' && !submittable) return;\n\n\t\tdocument\n\t\t\t.querySelector(`[data-key=\"${event.key}\" i]`)\n\t\t\t?.dispatchEvent(new MouseEvent('click', { cancelable: true }));\n\t}\n</script>\n\n<svelte:window on:keydown={keydown} />\n\n<svelte:head>\n\t<title>Sverdle</title>\n\t<meta name=\"description\" content=\"A Wordle clone written in SvelteKit\" />\n</svelte:head>\n\n<h1 class=\"visually-hidden\">Sverdle</h1>\n\n<form\n\tmethod=\"POST\"\n\taction=\"?/enter\"\n\tuse:enhance={() => {\n\t\t// prevent default callback from resetting the form\n\t\treturn ({ update }) => {\n\t\t\tupdate({ reset: false });\n\t\t};\n\t}}\n>\n\t<a class=\"how-to-play\" href=\"/sverdle/how-to-play\">How to play</a>\n\n\t<div class=\"grid\" class:playing={!won} class:bad-guess={form?.badGuess}>\n\t\t{#each Array.from(Array(6).keys()) as row (row)}\n\t\t\t{@const current = row === i}\n\t\t\t<h2 class=\"visually-hidden\">Row {row + 1}</h2>\n\t\t\t<div class=\"row\" class:current>\n\t\t\t\t{#each Array.from(Array(5).keys()) as column (column)}\n\t\t\t\t\t{@const guess = current ? currentGuess : data.guesses[row]}\n\t\t\t\t\t{@const answer = data.answers[row]?.[column]}\n\t\t\t\t\t{@const value = guess?.[column] ?? ''}\n\t\t\t\t\t{@const selected = current && column === guess.length}\n\t\t\t\t\t{@const exact = answer === 'x'}\n\t\t\t\t\t{@const close = answer === 'c'}\n\t\t\t\t\t{@const missing = answer === '_'}\n\t\t\t\t\t<div class=\"letter\" class:exact class:close class:missing class:selected>\n\t\t\t\t\t\t{value}\n\t\t\t\t\t\t<span class=\"visually-hidden\">\n\t\t\t\t\t\t\t{#if exact}\n\t\t\t\t\t\t\t\t(correct)\n\t\t\t\t\t\t\t{:else if close}\n\t\t\t\t\t\t\t\t(present)\n\t\t\t\t\t\t\t{:else if missing}\n\t\t\t\t\t\t\t\t(absent)\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\tempty\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input name=\"guess\" disabled={!current} type=\"hidden\" {value} />\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t<div class=\"controls\">\n\t\t{#if won || data.answers.length >= 6}\n\t\t\t{#if !won && data.answer}\n\t\t\t\t<p>the answer was \"{data.answer}\"</p>\n\t\t\t{/if}\n\t\t\t<button data-key=\"enter\" class=\"restart selected\" formaction=\"?/restart\">\n\t\t\t\t{won ? 'you won :)' : `game over :(`} play again?\n\t\t\t</button>\n\t\t{:else}\n\t\t\t<div class=\"keyboard\">\n\t\t\t\t<button data-key=\"enter\" class:selected={submittable} disabled={!submittable}>enter</button>\n\n\t\t\t\t<button\n\t\t\t\t\ton:click|preventDefault={update}\n\t\t\t\t\tdata-key=\"backspace\"\n\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\tname=\"key\"\n\t\t\t\t\tvalue=\"backspace\"\n\t\t\t\t>\n\t\t\t\t\tback\n\t\t\t\t</button>\n\n\t\t\t\t{#each ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'] as row}\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t{#each row as letter}\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ton:click|preventDefault={update}\n\t\t\t\t\t\t\t\tdata-key={letter}\n\t\t\t\t\t\t\t\tclass={classnames[letter]}\n\t\t\t\t\t\t\t\tdisabled={submittable}\n\t\t\t\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\t\t\t\tname=\"key\"\n\t\t\t\t\t\t\t\tvalue={letter}\n\t\t\t\t\t\t\t\taria-label=\"{letter} {description[letter] || ''}\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t{/each}\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/if}\n\t</div>\n</form>\n\n{#if won}\n\t<div\n\t\tstyle=\"position: absolute; left: 50%; top: 30%\"\n\t\tuse:confetti={{\n\t\t\tparticleCount: $reduced_motion ? 0 : undefined,\n\t\t\tforce: 0.7,\n\t\t\tstageWidth: window.innerWidth,\n\t\t\tstageHeight: window.innerHeight,\n\t\t\tcolors: ['#ff3e00', '#40b3ff', '#676778']\n\t\t}}\n\t></div>\n{/if}\n\n<style>\n\tform {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tgap: 1rem;\n\t\tflex: 1;\n\t}\n\n\t.how-to-play {\n\t\tcolor: var(--color-text);\n\t}\n\n\t.how-to-play::before {\n\t\tcontent: 'i';\n\t\tdisplay: inline-block;\n\t\tfont-size: 0.8em;\n\t\tfont-weight: 900;\n\t\twidth: 1em;\n\t\theight: 1em;\n\t\tpadding: 0.2em;\n\t\tline-height: 1;\n\t\tborder: 1.5px solid var(--color-text);\n\t\tborder-radius: 50%;\n\t\ttext-align: center;\n\t\tmargin: 0 0.5em 0 0;\n\t\tposition: relative;\n\t\ttop: -0.05em;\n\t}\n\n\t.grid {\n\t\t--width: min(100vw, 40vh, 380px);\n\t\tmax-width: var(--width);\n\t\talign-self: center;\n\t\tjustify-self: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: flex-start;\n\t}\n\n\t.grid .row {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(5, 1fr);\n\t\tgrid-gap: 0.2rem;\n\t\tmargin: 0 0 0.2rem 0;\n\t}\n\n\t@media (prefers-reduced-motion: no-preference) {\n\t\t.grid.bad-guess .row.current {\n\t\t\tanimation: wiggle 0.5s;\n\t\t}\n\t}\n\n\t.grid.playing .row.current {\n\t\tfilter: drop-shadow(3px 3px 10px var(--color-bg-0));\n\t}\n\n\t.letter {\n\t\taspect-ratio: 1;\n\t\twidth: 100%;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\ttext-align: center;\n\t\tbox-sizing: border-box;\n\t\ttext-transform: lowercase;\n\t\tborder: none;\n\t\tfont-size: calc(0.08 * var(--width));\n\t\tborder-radius: 2px;\n\t\tbackground: white;\n\t\tmargin: 0;\n\t\tcolor: rgba(0, 0, 0, 0.7);\n\t}\n\n\t.letter.missing {\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tcolor: rgba(0, 0, 0, 0.5);\n\t}\n\n\t.letter.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.letter.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.selected {\n\t\toutline: 2px solid var(--color-theme-1);\n\t}\n\n\t.controls {\n\t\ttext-align: center;\n\t\tjustify-content: center;\n\t\theight: min(18vh, 10rem);\n\t}\n\n\t.keyboard {\n\t\t--gap: 0.2rem;\n\t\tposition: relative;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: var(--gap);\n\t\theight: 100%;\n\t}\n\n\t.keyboard .row {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tgap: 0.2rem;\n\t\tflex: 1;\n\t}\n\n\t.keyboard button,\n\t.keyboard button:disabled {\n\t\t--size: min(8vw, 4vh, 40px);\n\t\tbackground-color: white;\n\t\tcolor: black;\n\t\twidth: var(--size);\n\t\tborder: none;\n\t\tborder-radius: 2px;\n\t\tfont-size: calc(var(--size) * 0.5);\n\t\tmargin: 0;\n\t}\n\n\t.keyboard button.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.keyboard button.missing {\n\t\topacity: 0.5;\n\t}\n\n\t.keyboard button.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.keyboard button:focus {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t.keyboard button[data-key='enter'],\n\t.keyboard button[data-key='backspace'] {\n\t\tposition: absolute;\n\t\tbottom: 0;\n\t\twidth: calc(1.5 * var(--size));\n\t\theight: calc(1 / 3 * (100% - 2 * var(--gap)));\n\t\ttext-transform: uppercase;\n\t\tfont-size: calc(0.3 * var(--size));\n\t\tpadding-top: calc(0.15 * var(--size));\n\t}\n\n\t.keyboard button[data-key='enter'] {\n\t\tright: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='backspace'] {\n\t\tleft: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='enter']:disabled {\n\t\topacity: 0.5;\n\t}\n\n\t.restart {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tborder-radius: 2px;\n\t\tborder: none;\n\t}\n\n\t.restart:focus,\n\t.restart:hover {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t@keyframes wiggle {\n\t\t0% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t\t10% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t30% {\n\t\t\ttransform: translateX(4px);\n\t\t}\n\t\t50% {\n\t\t\ttransform: translateX(-6px);\n\t\t}\n\t\t70% {\n\t\t\ttransform: translateX(+4px);\n\t\t}\n\t\t90% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t100% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t}\n</style>\n"
|
|
40
|
+
"contents": "<script>\n\timport { enhance } from '$app/forms';\n\timport { confetti } from '@neoconfetti/svelte';\n\n\timport { reducedMotion } from './reduced-motion';\n\n\t/**\n\t * @typedef {Object} Props\n\t * @property {import('./$types').PageData} data\n\t * @property {import('./$types').ActionData} form\n\t */\n\n\t/**\n\t * @type {Props}\n\t */\n\tlet { data, form = $bindable() } = $props();\n\n\t/** Whether or not the user has won */\n\tlet won = $derived(data.answers.at(-1) === 'xxxxx');\n\n\t/** The index of the current guess */\n\tlet i = $derived(won ? -1 : data.answers.length);\n\n\t/** The current guess */\n\t// svelte-ignore state_referenced_locally\n\tlet currentGuess = $state(data.guesses[i] || '');\n\n\t$effect(() => {\n\t\tcurrentGuess = data.guesses[i] || '';\n\t});\n\n\t/** Whether the current guess can be submitted */\n\tlet submittable = $derived(currentGuess.length === 5);\n\n\tconst { classnames, description } = $derived.by(() => {\n\t\t/**\n\t\t * A map of classnames for all letters that have been guessed,\n\t\t * used for styling the keyboard\n\t\t * @type {Record<string, 'exact' | 'close' | 'missing'>}\n\t\t */\n\t\tlet classnames = {};\n\t\t/**\n\t\t * A map of descriptions for all letters that have been guessed,\n\t\t * used for adding text for assistive technology (e.g. screen readers)\n\t\t * @type {Record<string, string>}\n\t\t */\n\t\tlet description = {};\n\t\tdata.answers.forEach((answer, i) => {\n\t\t\tconst guess = data.guesses[i];\n\t\t\tfor (let i = 0; i < 5; i += 1) {\n\t\t\t\tconst letter = guess[i];\n\t\t\t\tif (answer[i] === 'x') {\n\t\t\t\t\tclassnames[letter] = 'exact';\n\t\t\t\t\tdescription[letter] = 'correct';\n\t\t\t\t} else if (!classnames[letter]) {\n\t\t\t\t\tclassnames[letter] = answer[i] === 'c' ? 'close' : 'missing';\n\t\t\t\t\tdescription[letter] = answer[i] === 'c' ? 'present' : 'absent';\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn { classnames, description };\n\t});\n\n\t/**\n\t * Modify the game state without making a trip to the server,\n\t * if client-side JavaScript is enabled\n\t * @param {MouseEvent} event\n\t */\n\tfunction update(event) {\n\t\tevent.preventDefault();\n\t\tconst key = /** @type {HTMLButtonElement} */ (event.target).getAttribute('data-key');\n\n\t\tif (key === 'backspace') {\n\t\t\tcurrentGuess = currentGuess.slice(0, -1);\n\t\t\tif (form?.badGuess) form.badGuess = false;\n\t\t} else if (currentGuess.length < 5) {\n\t\t\tcurrentGuess += key;\n\t\t}\n\t}\n\n\t/**\n\t * Trigger form logic in response to a keydown event, so that\n\t * desktop users can use the keyboard to play the game\n\t * @param {KeyboardEvent} event\n\t */\n\tfunction keydown(event) {\n\t\tif (event.metaKey) return;\n\n\t\tif (event.key === 'Enter' && !submittable) return;\n\n\t\tdocument\n\t\t\t.querySelector(`[data-key=\"${event.key}\" i]`)\n\t\t\t?.dispatchEvent(new MouseEvent('click', { cancelable: true }));\n\t}\n</script>\n\n<svelte:window onkeydown={keydown} />\n\n<svelte:head>\n\t<title>Sverdle</title>\n\t<meta name=\"description\" content=\"A Wordle clone written in SvelteKit\" />\n</svelte:head>\n\n<h1 class=\"visually-hidden\">Sverdle</h1>\n\n<form\n\tmethod=\"POST\"\n\taction=\"?/enter\"\n\tuse:enhance={() => {\n\t\t// prevent default callback from resetting the form\n\t\treturn ({ update }) => {\n\t\t\tupdate({ reset: false });\n\t\t};\n\t}}\n>\n\t<a class=\"how-to-play\" href=\"/sverdle/how-to-play\">How to play</a>\n\n\t<div class=\"grid\" class:playing={!won} class:bad-guess={form?.badGuess}>\n\t\t{#each Array.from(Array(6).keys()) as row (row)}\n\t\t\t{@const current = row === i}\n\t\t\t<h2 class=\"visually-hidden\">Row {row + 1}</h2>\n\t\t\t<div class=\"row\" class:current>\n\t\t\t\t{#each Array.from(Array(5).keys()) as column (column)}\n\t\t\t\t\t{@const guess = current ? currentGuess : data.guesses[row]}\n\t\t\t\t\t{@const answer = data.answers[row]?.[column]}\n\t\t\t\t\t{@const value = guess?.[column] ?? ''}\n\t\t\t\t\t{@const selected = current && column === guess.length}\n\t\t\t\t\t{@const exact = answer === 'x'}\n\t\t\t\t\t{@const close = answer === 'c'}\n\t\t\t\t\t{@const missing = answer === '_'}\n\t\t\t\t\t<div class=\"letter\" class:exact class:close class:missing class:selected>\n\t\t\t\t\t\t{value}\n\t\t\t\t\t\t<span class=\"visually-hidden\">\n\t\t\t\t\t\t\t{#if exact}\n\t\t\t\t\t\t\t\t(correct)\n\t\t\t\t\t\t\t{:else if close}\n\t\t\t\t\t\t\t\t(present)\n\t\t\t\t\t\t\t{:else if missing}\n\t\t\t\t\t\t\t\t(absent)\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\tempty\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input name=\"guess\" disabled={!current} type=\"hidden\" {value} />\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t<div class=\"controls\">\n\t\t{#if won || data.answers.length >= 6}\n\t\t\t{#if !won && data.answer}\n\t\t\t\t<p>the answer was \"{data.answer}\"</p>\n\t\t\t{/if}\n\t\t\t<button data-key=\"enter\" class=\"restart selected\" formaction=\"?/restart\">\n\t\t\t\t{won ? 'you won :)' : `game over :(`} play again?\n\t\t\t</button>\n\t\t{:else}\n\t\t\t<div class=\"keyboard\">\n\t\t\t\t<button data-key=\"enter\" class:selected={submittable} disabled={!submittable}>enter</button>\n\n\t\t\t\t<button\n\t\t\t\t\tonclick={update}\n\t\t\t\t\tdata-key=\"backspace\"\n\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\tname=\"key\"\n\t\t\t\t\tvalue=\"backspace\"\n\t\t\t\t>\n\t\t\t\t\tback\n\t\t\t\t</button>\n\n\t\t\t\t{#each ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'] as row}\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t{#each row as letter}\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonclick={update}\n\t\t\t\t\t\t\t\tdata-key={letter}\n\t\t\t\t\t\t\t\tclass={classnames[letter]}\n\t\t\t\t\t\t\t\tdisabled={submittable}\n\t\t\t\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\t\t\t\tname=\"key\"\n\t\t\t\t\t\t\t\tvalue={letter}\n\t\t\t\t\t\t\t\taria-label=\"{letter} {description[letter] || ''}\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t{/each}\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/if}\n\t</div>\n</form>\n\n{#if won}\n\t<div\n\t\tstyle=\"position: absolute; left: 50%; top: 30%\"\n\t\tuse:confetti={{\n\t\t\tparticleCount: $reducedMotion ? 0 : undefined,\n\t\t\tforce: 0.7,\n\t\t\tstageWidth: window.innerWidth,\n\t\t\tstageHeight: window.innerHeight,\n\t\t\tcolors: ['#ff3e00', '#40b3ff', '#676778']\n\t\t}}\n\t></div>\n{/if}\n\n<style>\n\tform {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tgap: 1rem;\n\t\tflex: 1;\n\t}\n\n\t.how-to-play {\n\t\tcolor: var(--color-text);\n\t}\n\n\t.how-to-play::before {\n\t\tcontent: 'i';\n\t\tdisplay: inline-block;\n\t\tfont-size: 0.8em;\n\t\tfont-weight: 900;\n\t\twidth: 1em;\n\t\theight: 1em;\n\t\tpadding: 0.2em;\n\t\tline-height: 1;\n\t\tborder: 1.5px solid var(--color-text);\n\t\tborder-radius: 50%;\n\t\ttext-align: center;\n\t\tmargin: 0 0.5em 0 0;\n\t\tposition: relative;\n\t\ttop: -0.05em;\n\t}\n\n\t.grid {\n\t\t--width: min(100vw, 40vh, 380px);\n\t\tmax-width: var(--width);\n\t\talign-self: center;\n\t\tjustify-self: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: flex-start;\n\t}\n\n\t.grid .row {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(5, 1fr);\n\t\tgrid-gap: 0.2rem;\n\t\tmargin: 0 0 0.2rem 0;\n\t}\n\n\t@media (prefers-reduced-motion: no-preference) {\n\t\t.grid.bad-guess .row.current {\n\t\t\tanimation: wiggle 0.5s;\n\t\t}\n\t}\n\n\t.grid.playing .row.current {\n\t\tfilter: drop-shadow(3px 3px 10px var(--color-bg-0));\n\t}\n\n\t.letter {\n\t\taspect-ratio: 1;\n\t\twidth: 100%;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\ttext-align: center;\n\t\tbox-sizing: border-box;\n\t\ttext-transform: lowercase;\n\t\tborder: none;\n\t\tfont-size: calc(0.08 * var(--width));\n\t\tborder-radius: 2px;\n\t\tbackground: white;\n\t\tmargin: 0;\n\t\tcolor: rgba(0, 0, 0, 0.7);\n\t}\n\n\t.letter.missing {\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tcolor: rgba(0, 0, 0, 0.5);\n\t}\n\n\t.letter.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.letter.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.selected {\n\t\toutline: 2px solid var(--color-theme-1);\n\t}\n\n\t.controls {\n\t\ttext-align: center;\n\t\tjustify-content: center;\n\t\theight: min(18vh, 10rem);\n\t}\n\n\t.keyboard {\n\t\t--gap: 0.2rem;\n\t\tposition: relative;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: var(--gap);\n\t\theight: 100%;\n\t}\n\n\t.keyboard .row {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tgap: 0.2rem;\n\t\tflex: 1;\n\t}\n\n\t.keyboard button,\n\t.keyboard button:disabled {\n\t\t--size: min(8vw, 4vh, 40px);\n\t\tbackground-color: white;\n\t\tcolor: black;\n\t\twidth: var(--size);\n\t\tborder: none;\n\t\tborder-radius: 2px;\n\t\tfont-size: calc(var(--size) * 0.5);\n\t\tmargin: 0;\n\t}\n\n\t.keyboard button.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.keyboard button.missing {\n\t\topacity: 0.5;\n\t}\n\n\t.keyboard button.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.keyboard button:focus {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t.keyboard button[data-key='enter'],\n\t.keyboard button[data-key='backspace'] {\n\t\tposition: absolute;\n\t\tbottom: 0;\n\t\twidth: calc(1.5 * var(--size));\n\t\theight: calc(1 / 3 * (100% - 2 * var(--gap)));\n\t\ttext-transform: uppercase;\n\t\tfont-size: calc(0.3 * var(--size));\n\t\tpadding-top: calc(0.15 * var(--size));\n\t}\n\n\t.keyboard button[data-key='enter'] {\n\t\tright: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='backspace'] {\n\t\tleft: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='enter']:disabled {\n\t\topacity: 0.5;\n\t}\n\n\t.restart {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tborder-radius: 2px;\n\t\tborder: none;\n\t}\n\n\t.restart:focus,\n\t.restart:hover {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t@keyframes wiggle {\n\t\t0% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t\t10% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t30% {\n\t\t\ttransform: translateX(4px);\n\t\t}\n\t\t50% {\n\t\t\ttransform: translateX(-6px);\n\t\t}\n\t\t70% {\n\t\t\ttransform: translateX(+4px);\n\t\t}\n\t\t90% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t100% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t}\n</style>\n"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"name": "src/routes/sverdle/game.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"name": "src/routes/sverdle/reduced-motion.js",
|
|
56
|
-
"contents": "import { readable } from 'svelte/store';\nimport { browser } from '$app/environment';\n\nconst
|
|
56
|
+
"contents": "import { readable } from 'svelte/store';\nimport { browser } from '$app/environment';\n\nconst reducedMotionQuery = '(prefers-reduced-motion: reduce)';\n\nconst getInitialMotionPreference = () => {\n\tif (!browser) return false;\n\treturn window.matchMedia(reducedMotionQuery).matches;\n};\n\nexport const reducedMotion = readable(getInitialMotionPreference(), (set) => {\n\tif (browser) {\n\t\t/**\n\t\t * @param {MediaQueryListEvent} event\n\t\t */\n\t\tconst setReducedMotion = (event) => {\n\t\t\tset(event.matches);\n\t\t};\n\t\tconst mediaQueryList = window.matchMedia(reducedMotionQuery);\n\t\tmediaQueryList.addEventListener('change', setReducedMotion);\n\n\t\treturn () => {\n\t\t\tmediaQueryList.removeEventListener('change', setReducedMotion);\n\t\t};\n\t}\n});\n"
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"name": "src/routes/sverdle/words.server.js",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"name": "src/routes/+layout.svelte",
|
|
4
|
-
"contents": "<script>\n\timport Header from './Header.svelte';\n\timport '../app.css';\n</script>\n\n<div class=\"app\">\n\t<Header />\n\n\t<main>\n\t\t
|
|
4
|
+
"contents": "<script>\n\timport Header from './Header.svelte';\n\timport '../app.css';\n\n\tlet { children } = $props();\n</script>\n\n<div class=\"app\">\n\t<Header />\n\n\t<main>\n\t\t{@render children()}\n\t</main>\n\n\t<footer>\n\t\t<p>\n\t\t\tvisit <a href=\"https://svelte.dev/docs/kit\">svelte.dev/docs/kit</a> to learn about SvelteKit\n\t\t</p>\n\t</footer>\n</div>\n\n<style>\n\t.app {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tmin-height: 100vh;\n\t}\n\n\tmain {\n\t\tflex: 1;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tpadding: 1rem;\n\t\twidth: 100%;\n\t\tmax-width: 64rem;\n\t\tmargin: 0 auto;\n\t\tbox-sizing: border-box;\n\t}\n\n\tfooter {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tpadding: 12px;\n\t}\n\n\tfooter a {\n\t\tfont-weight: bold;\n\t}\n\n\t@media (min-width: 480px) {\n\t\tfooter {\n\t\t\tpadding: 12px 0;\n\t\t}\n\t}\n</style>\n"
|
|
5
5
|
},
|
|
6
6
|
{
|
|
7
7
|
"name": "src/routes/+page.svelte",
|
|
8
|
-
"contents": "<script>\n\timport Counter from './Counter.svelte';\n\timport welcome from '$lib/images/svelte-welcome.webp';\n\timport
|
|
8
|
+
"contents": "<script>\n\timport Counter from './Counter.svelte';\n\timport welcome from '$lib/images/svelte-welcome.webp';\n\timport welcomeFallback from '$lib/images/svelte-welcome.png';\n</script>\n\n<svelte:head>\n\t<title>Home</title>\n\t<meta name=\"description\" content=\"Svelte demo app\" />\n</svelte:head>\n\n<section>\n\t<h1>\n\t\t<span class=\"welcome\">\n\t\t\t<picture>\n\t\t\t\t<source srcset={welcome} type=\"image/webp\" />\n\t\t\t\t<img src={welcomeFallback} alt=\"Welcome\" />\n\t\t\t</picture>\n\t\t</span>\n\n\t\tto your new<br />SvelteKit app\n\t</h1>\n\n\t<h2>\n\t\ttry editing <strong>src/routes/+page.svelte</strong>\n\t</h2>\n\n\t<Counter />\n</section>\n\n<style>\n\tsection {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tflex: 0.6;\n\t}\n\n\th1 {\n\t\twidth: 100%;\n\t}\n\n\t.welcome {\n\t\tdisplay: block;\n\t\tposition: relative;\n\t\twidth: 100%;\n\t\theight: 0;\n\t\tpadding: 0 0 calc(100% * 495 / 2048) 0;\n\t}\n\n\t.welcome img {\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\ttop: 0;\n\t\tdisplay: block;\n\t}\n</style>\n"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"name": "src/routes/+page.js",
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": "src/routes/Counter.svelte",
|
|
16
|
-
"contents": "<script>\n\timport { spring } from 'svelte/motion';\n\n\tlet count = 0;\n\n\tconst
|
|
16
|
+
"contents": "<script>\n\timport { spring } from 'svelte/motion';\n\n\tlet count = $state(0);\n\n\t// svelte-ignore state_referenced_locally\n\tconst displayedCount = spring(count);\n\n\t$effect(() => {\n\t\tdisplayedCount.set(count);\n\t});\n\tlet offset = $derived(modulo($displayedCount, 1));\n\n\tfunction modulo(n, m) {\n\t\t// handle negative numbers\n\t\treturn ((n % m) + m) % m;\n\t}\n</script>\n\n<div class=\"counter\">\n\t<button onclick={() => (count -= 1)} aria-label=\"Decrease the counter by one\">\n\t\t<svg aria-hidden=\"true\" viewBox=\"0 0 1 1\">\n\t\t\t<path d=\"M0,0.5 L1,0.5\" />\n\t\t</svg>\n\t</button>\n\n\t<div class=\"counter-viewport\">\n\t\t<div class=\"counter-digits\" style=\"transform: translate(0, {100 * offset}%)\">\n\t\t\t<strong class=\"hidden\" aria-hidden=\"true\">{Math.floor($displayedCount + 1)}</strong>\n\t\t\t<strong>{Math.floor($displayedCount)}</strong>\n\t\t</div>\n\t</div>\n\n\t<button onclick={() => (count += 1)} aria-label=\"Increase the counter by one\">\n\t\t<svg aria-hidden=\"true\" viewBox=\"0 0 1 1\">\n\t\t\t<path d=\"M0,0.5 L1,0.5 M0.5,0 L0.5,1\" />\n\t\t</svg>\n\t</button>\n</div>\n\n<style>\n\t.counter {\n\t\tdisplay: flex;\n\t\tborder-top: 1px solid rgba(0, 0, 0, 0.1);\n\t\tborder-bottom: 1px solid rgba(0, 0, 0, 0.1);\n\t\tmargin: 1rem 0;\n\t}\n\n\t.counter button {\n\t\twidth: 2em;\n\t\tpadding: 0;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tborder: 0;\n\t\tbackground-color: transparent;\n\t\ttouch-action: manipulation;\n\t\tfont-size: 2rem;\n\t}\n\n\t.counter button:hover {\n\t\tbackground-color: var(--color-bg-1);\n\t}\n\n\tsvg {\n\t\twidth: 25%;\n\t\theight: 25%;\n\t}\n\n\tpath {\n\t\tvector-effect: non-scaling-stroke;\n\t\tstroke-width: 2px;\n\t\tstroke: #444;\n\t}\n\n\t.counter-viewport {\n\t\twidth: 8em;\n\t\theight: 4em;\n\t\toverflow: hidden;\n\t\ttext-align: center;\n\t\tposition: relative;\n\t}\n\n\t.counter-viewport strong {\n\t\tposition: absolute;\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tfont-weight: 400;\n\t\tcolor: var(--color-theme-1);\n\t\tfont-size: 4rem;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t}\n\n\t.counter-digits {\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t}\n\n\t.hidden {\n\t\ttop: -100%;\n\t\tuser-select: none;\n\t}\n</style>\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"name": "src/routes/Header.svelte",
|
|
20
|
-
"contents": "<script>\n\timport { page } from '$app/stores';\n\timport logo from '$lib/images/svelte-logo.svg';\n\timport github from '$lib/images/github.svg';\n</script>\n\n<header>\n\t<div class=\"corner\">\n\t\t<a href=\"https://
|
|
20
|
+
"contents": "<script>\n\timport { page } from '$app/stores';\n\timport logo from '$lib/images/svelte-logo.svg';\n\timport github from '$lib/images/github.svg';\n</script>\n\n<header>\n\t<div class=\"corner\">\n\t\t<a href=\"https://svelte.dev/docs/kit\">\n\t\t\t<img src={logo} alt=\"SvelteKit\" />\n\t\t</a>\n\t</div>\n\n\t<nav>\n\t\t<svg viewBox=\"0 0 2 3\" aria-hidden=\"true\">\n\t\t\t<path d=\"M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z\" />\n\t\t</svg>\n\t\t<ul>\n\t\t\t<li aria-current={$page.url.pathname === '/' ? 'page' : undefined}>\n\t\t\t\t<a href=\"/\">Home</a>\n\t\t\t</li>\n\t\t\t<li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>\n\t\t\t\t<a href=\"/about\">About</a>\n\t\t\t</li>\n\t\t\t<li aria-current={$page.url.pathname.startsWith('/sverdle') ? 'page' : undefined}>\n\t\t\t\t<a href=\"/sverdle\">Sverdle</a>\n\t\t\t</li>\n\t\t</ul>\n\t\t<svg viewBox=\"0 0 2 3\" aria-hidden=\"true\">\n\t\t\t<path d=\"M0,0 L0,3 C0.5,3 0.5,3 1,2 L2,0 Z\" />\n\t\t</svg>\n\t</nav>\n\n\t<div class=\"corner\">\n\t\t<a href=\"https://github.com/sveltejs/kit\">\n\t\t\t<img src={github} alt=\"GitHub\" />\n\t\t</a>\n\t</div>\n</header>\n\n<style>\n\theader {\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n\t}\n\n\t.corner {\n\t\twidth: 3em;\n\t\theight: 3em;\n\t}\n\n\t.corner a {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t}\n\n\t.corner img {\n\t\twidth: 2em;\n\t\theight: 2em;\n\t\tobject-fit: contain;\n\t}\n\n\tnav {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\t--background: rgba(255, 255, 255, 0.7);\n\t}\n\n\tsvg {\n\t\twidth: 2em;\n\t\theight: 3em;\n\t\tdisplay: block;\n\t}\n\n\tpath {\n\t\tfill: var(--background);\n\t}\n\n\tul {\n\t\tposition: relative;\n\t\tpadding: 0;\n\t\tmargin: 0;\n\t\theight: 3em;\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tlist-style: none;\n\t\tbackground: var(--background);\n\t\tbackground-size: contain;\n\t}\n\n\tli {\n\t\tposition: relative;\n\t\theight: 100%;\n\t}\n\n\tli[aria-current='page']::before {\n\t\t--size: 6px;\n\t\tcontent: '';\n\t\twidth: 0;\n\t\theight: 0;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: calc(50% - var(--size));\n\t\tborder: var(--size) solid transparent;\n\t\tborder-top: var(--size) solid var(--color-theme-1);\n\t}\n\n\tnav a {\n\t\tdisplay: flex;\n\t\theight: 100%;\n\t\talign-items: center;\n\t\tpadding: 0 0.5rem;\n\t\tcolor: var(--color-text);\n\t\tfont-weight: 700;\n\t\tfont-size: 0.8rem;\n\t\ttext-transform: uppercase;\n\t\tletter-spacing: 0.1em;\n\t\ttext-decoration: none;\n\t\ttransition: color 0.2s linear;\n\t}\n\n\ta:hover {\n\t\tcolor: var(--color-theme-1);\n\t}\n</style>\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"name": "src/routes/about/+page.svelte",
|
|
24
|
-
"contents": "<svelte:head>\n\t<title>About</title>\n\t<meta name=\"description\" content=\"About this app\" />\n</svelte:head>\n\n<div class=\"text-column\">\n\t<h1>About this app</h1>\n\n\t<p>\n\t\tThis is a <a href=\"https://
|
|
24
|
+
"contents": "<svelte:head>\n\t<title>About</title>\n\t<meta name=\"description\" content=\"About this app\" />\n</svelte:head>\n\n<div class=\"text-column\">\n\t<h1>About this app</h1>\n\n\t<p>\n\t\tThis is a <a href=\"https://svelte.dev/docs/kit\">SvelteKit</a> app. You can make your own by typing\n\t\tthe following into your command line and following the prompts:\n\t</p>\n\n\t<pre>npx sv create</pre>\n\n\t<p>\n\t\tThe page you're looking at is purely static HTML, with no client-side interactivity needed.\n\t\tBecause of that, we don't need to load any JavaScript. Try viewing the page's source, or opening\n\t\tthe devtools network panel and reloading.\n\t</p>\n\n\t<p>\n\t\tThe <a href=\"/sverdle\">Sverdle</a> page illustrates SvelteKit's data loading and form handling. Try\n\t\tusing it with JavaScript disabled!\n\t</p>\n</div>\n"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"name": "src/routes/about/+page.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"name": "src/routes/sverdle/+page.svelte",
|
|
36
|
-
"contents": "<script>\n\timport { confetti } from '@neoconfetti/svelte';\n\timport { enhance } from '$app/forms';\n\n\timport { reduced_motion } from './reduced-motion';\n\n\texport let data;\n\n\texport let form;\n\n\t/** Whether or not the user has won */\n\t$: won = data.answers.at(-1) === 'xxxxx';\n\n\t/** The index of the current guess */\n\t$: i = won ? -1 : data.answers.length;\n\n\t/** The current guess */\n\t$: currentGuess = data.guesses[i] || '';\n\n\t/** Whether the current guess can be submitted */\n\t$: submittable = currentGuess.length === 5;\n\n\t/**\n\t * A map of classnames for all letters that have been guessed,\n\t * used for styling the keyboard\n\t */\n\tlet classnames;\n\n\t/**\n\t * A map of descriptions for all letters that have been guessed,\n\t * used for adding text for assistive technology (e.g. screen readers)\n\t */\n\tlet description;\n\n\t$: {\n\t\tclassnames = {};\n\t\tdescription = {};\n\n\t\tdata.answers.forEach((answer, i) => {\n\t\t\tconst guess = data.guesses[i];\n\n\t\t\tfor (let i = 0; i < 5; i += 1) {\n\t\t\t\tconst letter = guess[i];\n\n\t\t\t\tif (answer[i] === 'x') {\n\t\t\t\t\tclassnames[letter] = 'exact';\n\t\t\t\t\tdescription[letter] = 'correct';\n\t\t\t\t} else if (!classnames[letter]) {\n\t\t\t\t\tclassnames[letter] = answer[i] === 'c' ? 'close' : 'missing';\n\t\t\t\t\tdescription[letter] = answer[i] === 'c' ? 'present' : 'absent';\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Modify the game state without making a trip to the server,\n\t * if client-side JavaScript is enabled\n\t */\n\tfunction update(event) {\n\t\tconst key = (event.target).getAttribute('data-key');\n\n\t\tif (key === 'backspace') {\n\t\t\tcurrentGuess = currentGuess.slice(0, -1);\n\t\t\tif (form?.badGuess) form.badGuess = false;\n\t\t} else if (currentGuess.length < 5) {\n\t\t\tcurrentGuess += key;\n\t\t}\n\t}\n\n\t/**\n\t * Trigger form logic in response to a keydown event, so that\n\t * desktop users can use the keyboard to play the game\n\t */\n\tfunction keydown(event) {\n\t\tif (event.metaKey) return;\n\n\t\tif (event.key === 'Enter' && !submittable) return;\n\n\t\tdocument\n\t\t\t.querySelector(`[data-key=\"${event.key}\" i]`)\n\t\t\t?.dispatchEvent(new MouseEvent('click', { cancelable: true }));\n\t}\n</script>\n\n<svelte:window on:keydown={keydown} />\n\n<svelte:head>\n\t<title>Sverdle</title>\n\t<meta name=\"description\" content=\"A Wordle clone written in SvelteKit\" />\n</svelte:head>\n\n<h1 class=\"visually-hidden\">Sverdle</h1>\n\n<form\n\tmethod=\"POST\"\n\taction=\"?/enter\"\n\tuse:enhance={() => {\n\t\t// prevent default callback from resetting the form\n\t\treturn ({ update }) => {\n\t\t\tupdate({ reset: false });\n\t\t};\n\t}}\n>\n\t<a class=\"how-to-play\" href=\"/sverdle/how-to-play\">How to play</a>\n\n\t<div class=\"grid\" class:playing={!won} class:bad-guess={form?.badGuess}>\n\t\t{#each Array.from(Array(6).keys()) as row (row)}\n\t\t\t{@const current = row === i}\n\t\t\t<h2 class=\"visually-hidden\">Row {row + 1}</h2>\n\t\t\t<div class=\"row\" class:current>\n\t\t\t\t{#each Array.from(Array(5).keys()) as column (column)}\n\t\t\t\t\t{@const guess = current ? currentGuess : data.guesses[row]}\n\t\t\t\t\t{@const answer = data.answers[row]?.[column]}\n\t\t\t\t\t{@const value = guess?.[column] ?? ''}\n\t\t\t\t\t{@const selected = current && column === guess.length}\n\t\t\t\t\t{@const exact = answer === 'x'}\n\t\t\t\t\t{@const close = answer === 'c'}\n\t\t\t\t\t{@const missing = answer === '_'}\n\t\t\t\t\t<div class=\"letter\" class:exact class:close class:missing class:selected>\n\t\t\t\t\t\t{value}\n\t\t\t\t\t\t<span class=\"visually-hidden\">\n\t\t\t\t\t\t\t{#if exact}\n\t\t\t\t\t\t\t\t(correct)\n\t\t\t\t\t\t\t{:else if close}\n\t\t\t\t\t\t\t\t(present)\n\t\t\t\t\t\t\t{:else if missing}\n\t\t\t\t\t\t\t\t(absent)\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\tempty\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input name=\"guess\" disabled={!current} type=\"hidden\" {value} />\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t<div class=\"controls\">\n\t\t{#if won || data.answers.length >= 6}\n\t\t\t{#if !won && data.answer}\n\t\t\t\t<p>the answer was \"{data.answer}\"</p>\n\t\t\t{/if}\n\t\t\t<button data-key=\"enter\" class=\"restart selected\" formaction=\"?/restart\">\n\t\t\t\t{won ? 'you won :)' : `game over :(`} play again?\n\t\t\t</button>\n\t\t{:else}\n\t\t\t<div class=\"keyboard\">\n\t\t\t\t<button data-key=\"enter\" class:selected={submittable} disabled={!submittable}>enter</button>\n\n\t\t\t\t<button\n\t\t\t\t\ton:click|preventDefault={update}\n\t\t\t\t\tdata-key=\"backspace\"\n\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\tname=\"key\"\n\t\t\t\t\tvalue=\"backspace\"\n\t\t\t\t>\n\t\t\t\t\tback\n\t\t\t\t</button>\n\n\t\t\t\t{#each ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'] as row}\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t{#each row as letter}\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ton:click|preventDefault={update}\n\t\t\t\t\t\t\t\tdata-key={letter}\n\t\t\t\t\t\t\t\tclass={classnames[letter]}\n\t\t\t\t\t\t\t\tdisabled={submittable}\n\t\t\t\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\t\t\t\tname=\"key\"\n\t\t\t\t\t\t\t\tvalue={letter}\n\t\t\t\t\t\t\t\taria-label=\"{letter} {description[letter] || ''}\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t{/each}\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/if}\n\t</div>\n</form>\n\n{#if won}\n\t<div\n\t\tstyle=\"position: absolute; left: 50%; top: 30%\"\n\t\tuse:confetti={{\n\t\t\tparticleCount: $reduced_motion ? 0 : undefined,\n\t\t\tforce: 0.7,\n\t\t\tstageWidth: window.innerWidth,\n\t\t\tstageHeight: window.innerHeight,\n\t\t\tcolors: ['#ff3e00', '#40b3ff', '#676778']\n\t\t}}\n\t></div>\n{/if}\n\n<style>\n\tform {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tgap: 1rem;\n\t\tflex: 1;\n\t}\n\n\t.how-to-play {\n\t\tcolor: var(--color-text);\n\t}\n\n\t.how-to-play::before {\n\t\tcontent: 'i';\n\t\tdisplay: inline-block;\n\t\tfont-size: 0.8em;\n\t\tfont-weight: 900;\n\t\twidth: 1em;\n\t\theight: 1em;\n\t\tpadding: 0.2em;\n\t\tline-height: 1;\n\t\tborder: 1.5px solid var(--color-text);\n\t\tborder-radius: 50%;\n\t\ttext-align: center;\n\t\tmargin: 0 0.5em 0 0;\n\t\tposition: relative;\n\t\ttop: -0.05em;\n\t}\n\n\t.grid {\n\t\t--width: min(100vw, 40vh, 380px);\n\t\tmax-width: var(--width);\n\t\talign-self: center;\n\t\tjustify-self: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: flex-start;\n\t}\n\n\t.grid .row {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(5, 1fr);\n\t\tgrid-gap: 0.2rem;\n\t\tmargin: 0 0 0.2rem 0;\n\t}\n\n\t@media (prefers-reduced-motion: no-preference) {\n\t\t.grid.bad-guess .row.current {\n\t\t\tanimation: wiggle 0.5s;\n\t\t}\n\t}\n\n\t.grid.playing .row.current {\n\t\tfilter: drop-shadow(3px 3px 10px var(--color-bg-0));\n\t}\n\n\t.letter {\n\t\taspect-ratio: 1;\n\t\twidth: 100%;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\ttext-align: center;\n\t\tbox-sizing: border-box;\n\t\ttext-transform: lowercase;\n\t\tborder: none;\n\t\tfont-size: calc(0.08 * var(--width));\n\t\tborder-radius: 2px;\n\t\tbackground: white;\n\t\tmargin: 0;\n\t\tcolor: rgba(0, 0, 0, 0.7);\n\t}\n\n\t.letter.missing {\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tcolor: rgba(0, 0, 0, 0.5);\n\t}\n\n\t.letter.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.letter.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.selected {\n\t\toutline: 2px solid var(--color-theme-1);\n\t}\n\n\t.controls {\n\t\ttext-align: center;\n\t\tjustify-content: center;\n\t\theight: min(18vh, 10rem);\n\t}\n\n\t.keyboard {\n\t\t--gap: 0.2rem;\n\t\tposition: relative;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: var(--gap);\n\t\theight: 100%;\n\t}\n\n\t.keyboard .row {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tgap: 0.2rem;\n\t\tflex: 1;\n\t}\n\n\t.keyboard button,\n\t.keyboard button:disabled {\n\t\t--size: min(8vw, 4vh, 40px);\n\t\tbackground-color: white;\n\t\tcolor: black;\n\t\twidth: var(--size);\n\t\tborder: none;\n\t\tborder-radius: 2px;\n\t\tfont-size: calc(var(--size) * 0.5);\n\t\tmargin: 0;\n\t}\n\n\t.keyboard button.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.keyboard button.missing {\n\t\topacity: 0.5;\n\t}\n\n\t.keyboard button.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.keyboard button:focus {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t.keyboard button[data-key='enter'],\n\t.keyboard button[data-key='backspace'] {\n\t\tposition: absolute;\n\t\tbottom: 0;\n\t\twidth: calc(1.5 * var(--size));\n\t\theight: calc(1 / 3 * (100% - 2 * var(--gap)));\n\t\ttext-transform: uppercase;\n\t\tfont-size: calc(0.3 * var(--size));\n\t\tpadding-top: calc(0.15 * var(--size));\n\t}\n\n\t.keyboard button[data-key='enter'] {\n\t\tright: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='backspace'] {\n\t\tleft: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='enter']:disabled {\n\t\topacity: 0.5;\n\t}\n\n\t.restart {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tborder-radius: 2px;\n\t\tborder: none;\n\t}\n\n\t.restart:focus,\n\t.restart:hover {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t@keyframes wiggle {\n\t\t0% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t\t10% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t30% {\n\t\t\ttransform: translateX(4px);\n\t\t}\n\t\t50% {\n\t\t\ttransform: translateX(-6px);\n\t\t}\n\t\t70% {\n\t\t\ttransform: translateX(+4px);\n\t\t}\n\t\t90% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t100% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t}\n</style>\n"
|
|
36
|
+
"contents": "<script>\n\timport { enhance } from '$app/forms';\n\timport { confetti } from '@neoconfetti/svelte';\n\n\timport { reducedMotion } from './reduced-motion';\n\n\tlet { data, form = $bindable() } = $props();\n\n\t/** Whether or not the user has won */\n\tlet won = $derived(data.answers.at(-1) === 'xxxxx');\n\n\t/** The index of the current guess */\n\tlet i = $derived(won ? -1 : data.answers.length);\n\n\t/** The current guess */\n\t// svelte-ignore state_referenced_locally\n\tlet currentGuess = $state(data.guesses[i] || '');\n\n\t$effect(() => {\n\t\tcurrentGuess = data.guesses[i] || '';\n\t});\n\n\t/** Whether the current guess can be submitted */\n\tlet submittable = $derived(currentGuess.length === 5);\n\n\tconst { classnames, description } = $derived.by(() => {\n\t\t/**\n\t\t * A map of classnames for all letters that have been guessed,\n\t\t * used for styling the keyboard\n\t\t */\n\t\tlet classnames = {};\n\t\t/**\n\t\t * A map of descriptions for all letters that have been guessed,\n\t\t * used for adding text for assistive technology (e.g. screen readers)\n\t\t */\n\t\tlet description = {};\n\t\tdata.answers.forEach((answer, i) => {\n\t\t\tconst guess = data.guesses[i];\n\t\t\tfor (let i = 0; i < 5; i += 1) {\n\t\t\t\tconst letter = guess[i];\n\t\t\t\tif (answer[i] === 'x') {\n\t\t\t\t\tclassnames[letter] = 'exact';\n\t\t\t\t\tdescription[letter] = 'correct';\n\t\t\t\t} else if (!classnames[letter]) {\n\t\t\t\t\tclassnames[letter] = answer[i] === 'c' ? 'close' : 'missing';\n\t\t\t\t\tdescription[letter] = answer[i] === 'c' ? 'present' : 'absent';\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn { classnames, description };\n\t});\n\n\t/**\n\t * Modify the game state without making a trip to the server,\n\t * if client-side JavaScript is enabled\n\t */\n\tfunction update(event) {\n\t\tevent.preventDefault();\n\t\tconst key = (event.target).getAttribute('data-key');\n\n\t\tif (key === 'backspace') {\n\t\t\tcurrentGuess = currentGuess.slice(0, -1);\n\t\t\tif (form?.badGuess) form.badGuess = false;\n\t\t} else if (currentGuess.length < 5) {\n\t\t\tcurrentGuess += key;\n\t\t}\n\t}\n\n\t/**\n\t * Trigger form logic in response to a keydown event, so that\n\t * desktop users can use the keyboard to play the game\n\t */\n\tfunction keydown(event) {\n\t\tif (event.metaKey) return;\n\n\t\tif (event.key === 'Enter' && !submittable) return;\n\n\t\tdocument\n\t\t\t.querySelector(`[data-key=\"${event.key}\" i]`)\n\t\t\t?.dispatchEvent(new MouseEvent('click', { cancelable: true }));\n\t}\n</script>\n\n<svelte:window onkeydown={keydown} />\n\n<svelte:head>\n\t<title>Sverdle</title>\n\t<meta name=\"description\" content=\"A Wordle clone written in SvelteKit\" />\n</svelte:head>\n\n<h1 class=\"visually-hidden\">Sverdle</h1>\n\n<form\n\tmethod=\"POST\"\n\taction=\"?/enter\"\n\tuse:enhance={() => {\n\t\t// prevent default callback from resetting the form\n\t\treturn ({ update }) => {\n\t\t\tupdate({ reset: false });\n\t\t};\n\t}}\n>\n\t<a class=\"how-to-play\" href=\"/sverdle/how-to-play\">How to play</a>\n\n\t<div class=\"grid\" class:playing={!won} class:bad-guess={form?.badGuess}>\n\t\t{#each Array.from(Array(6).keys()) as row (row)}\n\t\t\t{@const current = row === i}\n\t\t\t<h2 class=\"visually-hidden\">Row {row + 1}</h2>\n\t\t\t<div class=\"row\" class:current>\n\t\t\t\t{#each Array.from(Array(5).keys()) as column (column)}\n\t\t\t\t\t{@const guess = current ? currentGuess : data.guesses[row]}\n\t\t\t\t\t{@const answer = data.answers[row]?.[column]}\n\t\t\t\t\t{@const value = guess?.[column] ?? ''}\n\t\t\t\t\t{@const selected = current && column === guess.length}\n\t\t\t\t\t{@const exact = answer === 'x'}\n\t\t\t\t\t{@const close = answer === 'c'}\n\t\t\t\t\t{@const missing = answer === '_'}\n\t\t\t\t\t<div class=\"letter\" class:exact class:close class:missing class:selected>\n\t\t\t\t\t\t{value}\n\t\t\t\t\t\t<span class=\"visually-hidden\">\n\t\t\t\t\t\t\t{#if exact}\n\t\t\t\t\t\t\t\t(correct)\n\t\t\t\t\t\t\t{:else if close}\n\t\t\t\t\t\t\t\t(present)\n\t\t\t\t\t\t\t{:else if missing}\n\t\t\t\t\t\t\t\t(absent)\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\tempty\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input name=\"guess\" disabled={!current} type=\"hidden\" {value} />\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t<div class=\"controls\">\n\t\t{#if won || data.answers.length >= 6}\n\t\t\t{#if !won && data.answer}\n\t\t\t\t<p>the answer was \"{data.answer}\"</p>\n\t\t\t{/if}\n\t\t\t<button data-key=\"enter\" class=\"restart selected\" formaction=\"?/restart\">\n\t\t\t\t{won ? 'you won :)' : `game over :(`} play again?\n\t\t\t</button>\n\t\t{:else}\n\t\t\t<div class=\"keyboard\">\n\t\t\t\t<button data-key=\"enter\" class:selected={submittable} disabled={!submittable}>enter</button>\n\n\t\t\t\t<button\n\t\t\t\t\tonclick={update}\n\t\t\t\t\tdata-key=\"backspace\"\n\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\tname=\"key\"\n\t\t\t\t\tvalue=\"backspace\"\n\t\t\t\t>\n\t\t\t\t\tback\n\t\t\t\t</button>\n\n\t\t\t\t{#each ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'] as row}\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t{#each row as letter}\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonclick={update}\n\t\t\t\t\t\t\t\tdata-key={letter}\n\t\t\t\t\t\t\t\tclass={classnames[letter]}\n\t\t\t\t\t\t\t\tdisabled={submittable}\n\t\t\t\t\t\t\t\tformaction=\"?/update\"\n\t\t\t\t\t\t\t\tname=\"key\"\n\t\t\t\t\t\t\t\tvalue={letter}\n\t\t\t\t\t\t\t\taria-label=\"{letter} {description[letter] || ''}\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t{/each}\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/if}\n\t</div>\n</form>\n\n{#if won}\n\t<div\n\t\tstyle=\"position: absolute; left: 50%; top: 30%\"\n\t\tuse:confetti={{\n\t\t\tparticleCount: $reducedMotion ? 0 : undefined,\n\t\t\tforce: 0.7,\n\t\t\tstageWidth: window.innerWidth,\n\t\t\tstageHeight: window.innerHeight,\n\t\t\tcolors: ['#ff3e00', '#40b3ff', '#676778']\n\t\t}}\n\t></div>\n{/if}\n\n<style>\n\tform {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tgap: 1rem;\n\t\tflex: 1;\n\t}\n\n\t.how-to-play {\n\t\tcolor: var(--color-text);\n\t}\n\n\t.how-to-play::before {\n\t\tcontent: 'i';\n\t\tdisplay: inline-block;\n\t\tfont-size: 0.8em;\n\t\tfont-weight: 900;\n\t\twidth: 1em;\n\t\theight: 1em;\n\t\tpadding: 0.2em;\n\t\tline-height: 1;\n\t\tborder: 1.5px solid var(--color-text);\n\t\tborder-radius: 50%;\n\t\ttext-align: center;\n\t\tmargin: 0 0.5em 0 0;\n\t\tposition: relative;\n\t\ttop: -0.05em;\n\t}\n\n\t.grid {\n\t\t--width: min(100vw, 40vh, 380px);\n\t\tmax-width: var(--width);\n\t\talign-self: center;\n\t\tjustify-self: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: flex-start;\n\t}\n\n\t.grid .row {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: repeat(5, 1fr);\n\t\tgrid-gap: 0.2rem;\n\t\tmargin: 0 0 0.2rem 0;\n\t}\n\n\t@media (prefers-reduced-motion: no-preference) {\n\t\t.grid.bad-guess .row.current {\n\t\t\tanimation: wiggle 0.5s;\n\t\t}\n\t}\n\n\t.grid.playing .row.current {\n\t\tfilter: drop-shadow(3px 3px 10px var(--color-bg-0));\n\t}\n\n\t.letter {\n\t\taspect-ratio: 1;\n\t\twidth: 100%;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\ttext-align: center;\n\t\tbox-sizing: border-box;\n\t\ttext-transform: lowercase;\n\t\tborder: none;\n\t\tfont-size: calc(0.08 * var(--width));\n\t\tborder-radius: 2px;\n\t\tbackground: white;\n\t\tmargin: 0;\n\t\tcolor: rgba(0, 0, 0, 0.7);\n\t}\n\n\t.letter.missing {\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tcolor: rgba(0, 0, 0, 0.5);\n\t}\n\n\t.letter.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.letter.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.selected {\n\t\toutline: 2px solid var(--color-theme-1);\n\t}\n\n\t.controls {\n\t\ttext-align: center;\n\t\tjustify-content: center;\n\t\theight: min(18vh, 10rem);\n\t}\n\n\t.keyboard {\n\t\t--gap: 0.2rem;\n\t\tposition: relative;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tgap: var(--gap);\n\t\theight: 100%;\n\t}\n\n\t.keyboard .row {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tgap: 0.2rem;\n\t\tflex: 1;\n\t}\n\n\t.keyboard button,\n\t.keyboard button:disabled {\n\t\t--size: min(8vw, 4vh, 40px);\n\t\tbackground-color: white;\n\t\tcolor: black;\n\t\twidth: var(--size);\n\t\tborder: none;\n\t\tborder-radius: 2px;\n\t\tfont-size: calc(var(--size) * 0.5);\n\t\tmargin: 0;\n\t}\n\n\t.keyboard button.exact {\n\t\tbackground: var(--color-theme-2);\n\t\tcolor: white;\n\t}\n\n\t.keyboard button.missing {\n\t\topacity: 0.5;\n\t}\n\n\t.keyboard button.close {\n\t\tborder: 2px solid var(--color-theme-2);\n\t}\n\n\t.keyboard button:focus {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t.keyboard button[data-key='enter'],\n\t.keyboard button[data-key='backspace'] {\n\t\tposition: absolute;\n\t\tbottom: 0;\n\t\twidth: calc(1.5 * var(--size));\n\t\theight: calc(1 / 3 * (100% - 2 * var(--gap)));\n\t\ttext-transform: uppercase;\n\t\tfont-size: calc(0.3 * var(--size));\n\t\tpadding-top: calc(0.15 * var(--size));\n\t}\n\n\t.keyboard button[data-key='enter'] {\n\t\tright: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='backspace'] {\n\t\tleft: calc(50% + 3.5 * var(--size) + 0.8rem);\n\t}\n\n\t.keyboard button[data-key='enter']:disabled {\n\t\topacity: 0.5;\n\t}\n\n\t.restart {\n\t\twidth: 100%;\n\t\tpadding: 1rem;\n\t\tbackground: rgba(255, 255, 255, 0.5);\n\t\tborder-radius: 2px;\n\t\tborder: none;\n\t}\n\n\t.restart:focus,\n\t.restart:hover {\n\t\tbackground: var(--color-theme-1);\n\t\tcolor: white;\n\t\toutline: none;\n\t}\n\n\t@keyframes wiggle {\n\t\t0% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t\t10% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t30% {\n\t\t\ttransform: translateX(4px);\n\t\t}\n\t\t50% {\n\t\t\ttransform: translateX(-6px);\n\t\t}\n\t\t70% {\n\t\t\ttransform: translateX(+4px);\n\t\t}\n\t\t90% {\n\t\t\ttransform: translateX(-2px);\n\t\t}\n\t\t100% {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t}\n</style>\n"
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"name": "src/routes/sverdle/game.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"name": "src/routes/sverdle/reduced-motion.js",
|
|
52
|
-
"contents": "import { readable } from 'svelte/store';\nimport { browser } from '$app/environment';\n\nconst
|
|
52
|
+
"contents": "import { readable } from 'svelte/store';\nimport { browser } from '$app/environment';\n\nconst reducedMotionQuery = '(prefers-reduced-motion: reduce)';\n\nconst getInitialMotionPreference = () => {\n\tif (!browser) return false;\n\treturn window.matchMedia(reducedMotionQuery).matches;\n};\n\nexport const reducedMotion = readable(getInitialMotionPreference(), (set) => {\n\tif (browser) {\n\t\tconst setReducedMotion = (event) => {\n\t\t\tset(event.matches);\n\t\t};\n\t\tconst mediaQueryList = window.matchMedia(reducedMotionQuery);\n\t\tmediaQueryList.addEventListener('change', setReducedMotion);\n\n\t\treturn () => {\n\t\t\tmediaQueryList.removeEventListener('change', setReducedMotion);\n\t\t};\n\t}\n});\n"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"name": "src/routes/sverdle/words.server.js",
|