mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-17 04:09:40 +03:00
finish examples
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"preserveSymlinks": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
|
||||
@@ -1,44 +1,19 @@
|
||||
import { Component } from '@angular/core';
|
||||
import type { EventListenerArgs } from 'overlayscrollbars';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<!--The content below is only a placeholder and can be replaced.-->
|
||||
<div style="text-align:center" class="content">
|
||||
<h1>Welcome to {{ title }}!</h1>
|
||||
<span style="display: block">{{ title }} app is running!</span>
|
||||
<overlay-scrollbars style="width: 222px; height: 222px;">
|
||||
<img
|
||||
width="300"
|
||||
alt="Angular Logo"
|
||||
width="333"
|
||||
height="333"
|
||||
alt="Angular logo"
|
||||
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
|
||||
/>
|
||||
</div>
|
||||
<h2>Here are some links to help you start:</h2>
|
||||
<div overlay-scrollbars (osUpdated)="onUpdated($event)"></div>
|
||||
<ul>
|
||||
<li>
|
||||
<h2>
|
||||
<a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a>
|
||||
</h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2>
|
||||
<a target="_blank" rel="noopener" href="https://angular.io/cli">CLI Documentation</a>
|
||||
</h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
</overlay-scrollbars>
|
||||
`,
|
||||
styles: [],
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'example';
|
||||
|
||||
onUpdated([instance, onUpdatedArgs]: EventListenerArgs['updated']) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(instance, onUpdatedArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@ if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
@import '~overlayscrollbars/styles/overlayscrollbars.css';
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
||||
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body,
|
||||
app-root {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
Generated
+829
-802
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
"@types/node": "^16.11.68",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-react": "file:../../packages/overlayscrollbars-react/dist",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,15 @@
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<OverlayScrollbarsComponent msg="hi" />
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
</header>
|
||||
<OverlayScrollbarsComponent
|
||||
style={{ width: '222px', height: '222px' }}
|
||||
options={{ scrollbars: { theme: 'os-theme-light' } }}
|
||||
>
|
||||
<img src={logo} className="App-logo" alt="React logo" width="333" height="333" />
|
||||
</OverlayScrollbarsComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,34 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
||||
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
pointer-events: none;
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
|
||||
Generated
+12
@@ -5,6 +5,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-vue": "file:../../packages/overlayscrollbars-solid/dist",
|
||||
"solid-js": "^1.5.1"
|
||||
},
|
||||
@@ -23,6 +24,10 @@
|
||||
"solid-js": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"../../packages/overlayscrollbars/dist": {
|
||||
"version": "2.0.0-beta.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||
@@ -1255,6 +1260,10 @@
|
||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/overlayscrollbars": {
|
||||
"resolved": "../../packages/overlayscrollbars/dist",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/overlayscrollbars-vue": {
|
||||
"resolved": "../../packages/overlayscrollbars-solid/dist",
|
||||
"link": true
|
||||
@@ -2319,6 +2328,9 @@
|
||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
|
||||
"dev": true
|
||||
},
|
||||
"overlayscrollbars": {
|
||||
"version": "file:../../packages/overlayscrollbars/dist"
|
||||
},
|
||||
"overlayscrollbars-vue": {
|
||||
"version": "file:../../packages/overlayscrollbars-solid/dist",
|
||||
"requires": {}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-vue": "file:../../packages/overlayscrollbars-solid/dist",
|
||||
"solid-js": "^1.5.1"
|
||||
},
|
||||
|
||||
@@ -1,28 +1,8 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #b318f0;
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
|
||||
@@ -5,23 +5,12 @@ import logo from './logo.svg';
|
||||
|
||||
const App: Component = () => {
|
||||
return (
|
||||
<div class={styles.App}>
|
||||
<header class={styles.header}>
|
||||
<img src={logo} class={styles.logo} alt="logo" />
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to reload.
|
||||
</p>
|
||||
<OverlayScrollbarsComponent element="span" />
|
||||
<a
|
||||
class={styles.link}
|
||||
href="https://github.com/solidjs/solid"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn Solid
|
||||
</a>
|
||||
</header>
|
||||
</div>
|
||||
<OverlayScrollbarsComponent
|
||||
style={{ width: '222px', height: '222px' }}
|
||||
options={{ scrollbars: { theme: 'os-theme-light' } }}
|
||||
>
|
||||
<img src={logo} class={styles.logo} alt="logo" width="333" height="333" />
|
||||
</OverlayScrollbarsComponent>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
||||
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* @refresh reload */
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import { render } from 'solid-js/web';
|
||||
|
||||
import './index.css';
|
||||
|
||||
Generated
+53
-8
@@ -6,6 +6,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-svelte": "file:../../packages/overlayscrollbars-svelte/dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -22,6 +23,32 @@
|
||||
"vite": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"../../packages/overlayscrollbars-svelte/dist": {
|
||||
"name": "overlayscrollbars-svelte",
|
||||
"version": "0.4.0",
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"@sveltejs/package": "next",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.9",
|
||||
"@testing-library/svelte": "^3.2.2",
|
||||
"overlayscrollbars": "file:./../overlayscrollbars/dist",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte-check": "^2.7.1",
|
||||
"svelte-preprocess": "^4.10.6",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"overlayscrollbars": "^2.0.0",
|
||||
"svelte": "^3.44.0"
|
||||
}
|
||||
},
|
||||
"../../packages/overlayscrollbars/dist": {
|
||||
"name": "overlayscrollbars",
|
||||
"version": "2.0.0-beta.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@cloudflare/workers-types": {
|
||||
"version": "3.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-3.17.0.tgz",
|
||||
@@ -1542,12 +1569,13 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/overlayscrollbars": {
|
||||
"resolved": "../../packages/overlayscrollbars/dist",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/overlayscrollbars-svelte": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "file:../../packages/overlayscrollbars-svelte/dist",
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.44.0"
|
||||
}
|
||||
"resolved": "../../packages/overlayscrollbars-svelte/dist",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
@@ -1982,6 +2010,7 @@
|
||||
"version": "3.52.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.52.0.tgz",
|
||||
"integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
@@ -3346,9 +3375,24 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"overlayscrollbars": {
|
||||
"version": "file:../../packages/overlayscrollbars/dist"
|
||||
},
|
||||
"overlayscrollbars-svelte": {
|
||||
"version": "0.4.0",
|
||||
"requires": {}
|
||||
"version": "file:../../packages/overlayscrollbars-svelte/dist",
|
||||
"requires": {
|
||||
"@sveltejs/adapter-auto": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"@sveltejs/package": "next",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.9",
|
||||
"@testing-library/svelte": "^3.2.2",
|
||||
"overlayscrollbars": "file:../overlayscrollbars/dist",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte-check": "^2.7.1",
|
||||
"svelte-preprocess": "^4.10.6",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
@@ -3646,7 +3690,8 @@
|
||||
"svelte": {
|
||||
"version": "3.52.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.52.0.tgz",
|
||||
"integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ=="
|
||||
"integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte-check": {
|
||||
"version": "2.9.2",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-svelte": "file:../../packages/overlayscrollbars-svelte/dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3 -3 30 30">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5229 6.47715 22 12 22C17.5229 22 22 17.5229 22 12C22 6.47715 17.5229 2 12 2ZM0 12C0 5.3726 5.3726 0 12 0C18.6274 0 24 5.3726 24 12C24 18.6274 18.6274 24 12 24C5.3726 24 0 18.6274 0 12Z"
|
||||
fill="rgba(0,0,0,0.7)"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M9.59162 22.7357C9.49492 22.6109 9.49492 21.4986 9.59162 19.399C8.55572 19.4347 7.90122 19.3628 7.62812 19.1833C7.21852 18.9139 6.80842 18.0833 6.44457 17.4979C6.08072 16.9125 5.27312 16.8199 4.94702 16.6891C4.62091 16.5582 4.53905 16.0247 5.84562 16.4282C7.15222 16.8316 7.21592 17.9303 7.62812 18.1872C8.04032 18.4441 9.02572 18.3317 9.47242 18.1259C9.91907 17.9201 9.88622 17.1538 9.96587 16.8503C10.0666 16.5669 9.71162 16.5041 9.70382 16.5018C9.26777 16.5018 6.97697 16.0036 6.34772 13.7852C5.71852 11.5669 6.52907 10.117 6.96147 9.49369C7.24972 9.07814 7.22422 8.19254 6.88497 6.83679C8.11677 6.67939 9.06732 7.06709 9.73672 7.99999C9.73737 8.00534 10.6143 7.47854 12.0001 7.47854C13.386 7.47854 13.8777 7.90764 14.2571 7.99999C14.6365 8.09234 14.94 6.36699 17.2834 6.83679C16.7942 7.79839 16.3844 8.99999 16.6972 9.49369C17.0099 9.98739 18.2372 11.5573 17.4833 13.7852C16.9807 15.2706 15.9927 16.1761 14.5192 16.5018C14.3502 16.5557 14.2658 16.6427 14.2658 16.7627C14.2658 16.9427 14.4942 16.9624 14.8233 17.8058C15.0426 18.368 15.0585 19.9739 14.8708 22.6234C14.3953 22.7445 14.0254 22.8257 13.7611 22.8673C13.2924 22.9409 12.7835 22.9822 12.2834 22.9982C11.7834 23.0141 11.6098 23.0123 10.9185 22.948C10.4577 22.9051 10.0154 22.8343 9.59162 22.7357Z"
|
||||
fill="rgba(0,0,0,0.7)"
|
||||
stroke="none"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 352 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 113 KiB |
@@ -1,53 +1,10 @@
|
||||
<script>
|
||||
import Header from './Header.svelte';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import './styles.css';
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
<Header />
|
||||
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to learn SvelteKit</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
max-width: 64rem;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
footer a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
footer {
|
||||
padding: 12px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
@@ -1,7 +1,5 @@
|
||||
<script>
|
||||
import Counter from './Counter.svelte';
|
||||
import welcome from '$lib/images/svelte-welcome.webp';
|
||||
import welcome_fallback from '$lib/images/svelte-welcome.png';
|
||||
import logo from '$lib/images/logo.svg';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-svelte';
|
||||
</script>
|
||||
|
||||
@@ -10,52 +8,6 @@
|
||||
<meta name="description" content="Svelte demo app" />
|
||||
</svelte:head>
|
||||
|
||||
<section>
|
||||
<h1>
|
||||
<span class="welcome">
|
||||
<picture>
|
||||
<source srcset={welcome} type="image/webp" />
|
||||
<img src={welcome_fallback} alt="Welcome" />
|
||||
</picture>
|
||||
</span>
|
||||
|
||||
to your new<br />SvelteKit app
|
||||
</h1>
|
||||
|
||||
<h2>
|
||||
try editing <strong>src/routes/+page.svelte</strong>
|
||||
</h2>
|
||||
|
||||
<OverlayScrollbarsComponent />
|
||||
<Counter />
|
||||
</section>
|
||||
|
||||
<style>
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex: 0.6;
|
||||
}
|
||||
|
||||
h1 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding: 0 0 calc(100% * 495 / 2048) 0;
|
||||
}
|
||||
|
||||
.welcome img {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<OverlayScrollbarsComponent style="height: 222px; width: 222px" :options="options">
|
||||
<img src={logo} alt="Svelte Logo" width="333" height="333" />
|
||||
</OverlayScrollbarsComponent>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { spring } from 'svelte/motion';
|
||||
|
||||
let count = 0;
|
||||
|
||||
const displayed_count = spring();
|
||||
$: displayed_count.set(count);
|
||||
$: offset = modulo($displayed_count, 1);
|
||||
|
||||
function modulo(n: number, m: number) {
|
||||
// handle negative numbers
|
||||
return ((n % m) + m) % m;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="counter">
|
||||
<button on:click={() => (count -= 1)} aria-label="Decrease the counter by one">
|
||||
<svg aria-hidden="true" viewBox="0 0 1 1">
|
||||
<path d="M0,0.5 L1,0.5" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="counter-viewport">
|
||||
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
|
||||
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
|
||||
<strong>{Math.floor($displayed_count)}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button on:click={() => (count += 1)} aria-label="Increase the counter by one">
|
||||
<svg aria-hidden="true" viewBox="0 0 1 1">
|
||||
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
display: flex;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.counter button {
|
||||
width: 2em;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
touch-action: manipulation;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.counter button:hover {
|
||||
background-color: var(--color-bg-1);
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 25%;
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
path {
|
||||
vector-effect: non-scaling-stroke;
|
||||
stroke-width: 2px;
|
||||
stroke: #444;
|
||||
}
|
||||
|
||||
.counter-viewport {
|
||||
width: 8em;
|
||||
height: 4em;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.counter-viewport strong {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-weight: 400;
|
||||
color: var(--color-theme-1);
|
||||
font-size: 4rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.counter-digits {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
top: -100%;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
@@ -1,129 +0,0 @@
|
||||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import logo from '$lib/images/svelte-logo.svg';
|
||||
import github from '$lib/images/github.svg';
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<div class="corner">
|
||||
<a href="https://kit.svelte.dev">
|
||||
<img src={logo} alt="SvelteKit" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<svg viewBox="0 0 2 3" aria-hidden="true">
|
||||
<path d="M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z" />
|
||||
</svg>
|
||||
<ul>
|
||||
<li class:active={$page.url.pathname === '/'}>
|
||||
<a href="/">Home</a>
|
||||
</li>
|
||||
<li class:active={$page.url.pathname === '/about'}>
|
||||
<a href="/about">About</a>
|
||||
</li>
|
||||
<li class:active={$page.url.pathname.startsWith('/sverdle')}>
|
||||
<a href="/sverdle">Sverdle</a>
|
||||
</li>
|
||||
</ul>
|
||||
<svg viewBox="0 0 2 3" aria-hidden="true">
|
||||
<path d="M0,0 L0,3 C0.5,3 0.5,3 1,2 L2,0 Z" />
|
||||
</svg>
|
||||
</nav>
|
||||
|
||||
<div class="corner">
|
||||
<a href="https://github.com/sveltejs/kit">
|
||||
<img src={github} alt="GitHub" />
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.corner {
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.corner a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.corner img {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
--background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 2em;
|
||||
height: 3em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
path {
|
||||
fill: var(--background);
|
||||
}
|
||||
|
||||
ul {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 3em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
background: var(--background);
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
li.active::before {
|
||||
--size: 6px;
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - var(--size));
|
||||
border: var(--size) solid transparent;
|
||||
border-top: var(--size) solid var(--color-theme-1);
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
padding: 0 0.5rem;
|
||||
color: var(--color-text);
|
||||
font-weight: 700;
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s linear;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--color-theme-1);
|
||||
}
|
||||
</style>
|
||||
@@ -1,26 +0,0 @@
|
||||
<svelte:head>
|
||||
<title>About</title>
|
||||
<meta name="description" content="About this app" />
|
||||
</svelte:head>
|
||||
|
||||
<div class="text-column">
|
||||
<h1>About this app</h1>
|
||||
|
||||
<p>
|
||||
This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the
|
||||
following into your command line and following the prompts:
|
||||
</p>
|
||||
|
||||
<pre>npm create svelte@latest</pre>
|
||||
|
||||
<p>
|
||||
The page you're looking at is purely static HTML, with no client-side interactivity needed.
|
||||
Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening
|
||||
the devtools network panel and reloading.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/sverdle">Sverdle</a> page illustrates SvelteKit's data loading and form handling. Try
|
||||
using it with JavaScript disabled!
|
||||
</p>
|
||||
</div>
|
||||
@@ -1,9 +0,0 @@
|
||||
import { dev } from '$app/environment';
|
||||
|
||||
// we don't need any JS on this page, though we'll load
|
||||
// it in dev so that we get hot module replacement
|
||||
export const csr = dev;
|
||||
|
||||
// since there's no dynamic data here, we can prerender
|
||||
// it so that it gets served as a static asset in production
|
||||
export const prerender = true;
|
||||
@@ -1,95 +1,98 @@
|
||||
@import '@fontsource/fira-mono';
|
||||
|
||||
:root {
|
||||
--font-body: Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
||||
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
--font-mono: 'Fira Mono', monospace;
|
||||
--color-bg-0: rgb(202, 216, 228);
|
||||
--color-bg-1: hsl(209, 36%, 86%);
|
||||
--color-bg-2: hsl(224, 44%, 95%);
|
||||
--color-theme-1: #ff3e00;
|
||||
--color-theme-2: #40b3ff;
|
||||
--color-text: rgba(0, 0, 0, 0.7);
|
||||
--column-width: 42rem;
|
||||
--column-margin-top: 4rem;
|
||||
font-family: var(--font-body);
|
||||
color: var(--color-text);
|
||||
--font-body: Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
||||
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
--font-mono: 'Fira Mono', monospace;
|
||||
--color-bg-0: rgb(202, 216, 228);
|
||||
--color-bg-1: hsl(209, 36%, 86%);
|
||||
--color-bg-2: hsl(224, 44%, 95%);
|
||||
--color-theme-1: #ff3e00;
|
||||
--color-theme-2: #40b3ff;
|
||||
--color-text: rgba(0, 0, 0, 0.7);
|
||||
--column-width: 42rem;
|
||||
--column-margin-top: 4rem;
|
||||
font-family: var(--font-body);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
background-attachment: fixed;
|
||||
background-color: var(--color-bg-1);
|
||||
background-size: 100vw 100vh;
|
||||
background-image: radial-gradient(
|
||||
50% 50% at 50% 50%,
|
||||
rgba(255, 255, 255, 0.75) 0%,
|
||||
rgba(255, 255, 255, 0) 100%
|
||||
),
|
||||
linear-gradient(180deg, var(--color-bg-0) 0%, var(--color-bg-1) 15%, var(--color-bg-2) 50%);
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
background-attachment: fixed;
|
||||
background-color: var(--color-bg-1);
|
||||
background-size: 100vw 100vh;
|
||||
background-image: radial-gradient(
|
||||
50% 50% at 50% 50%,
|
||||
rgba(255, 255, 255, 0.75) 0%,
|
||||
rgba(255, 255, 255, 0) 100%
|
||||
),
|
||||
linear-gradient(180deg, var(--color-bg-0) 0%, var(--color-bg-1) 15%, var(--color-bg-2) 50%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-theme-1);
|
||||
text-decoration: none;
|
||||
color: var(--color-theme-1);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 16px;
|
||||
font-family: var(--font-mono);
|
||||
background-color: rgba(255, 255, 255, 0.45);
|
||||
border-radius: 3px;
|
||||
box-shadow: 2px 2px 6px rgb(255 255 255 / 25%);
|
||||
padding: 0.5em;
|
||||
overflow-x: auto;
|
||||
color: var(--color-text);
|
||||
font-size: 16px;
|
||||
font-family: var(--font-mono);
|
||||
background-color: rgba(255, 255, 255, 0.45);
|
||||
border-radius: 3px;
|
||||
box-shadow: 2px 2px 6px rgb(255 255 255 / 25%);
|
||||
padding: 0.5em;
|
||||
overflow-x: auto;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.text-column {
|
||||
display: flex;
|
||||
max-width: 48rem;
|
||||
flex: 0.6;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
max-width: 48rem;
|
||||
flex: 0.6;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@media (min-width: 720px) {
|
||||
h1 {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
import { invalid } from '@sveltejs/kit';
|
||||
import { words, allowed } from './words.server';
|
||||
import type { PageServerLoad, Actions } from './$types';
|
||||
|
||||
export const load: PageServerLoad = ({ cookies }) => {
|
||||
const game = new Game(cookies.get('sverdle'));
|
||||
|
||||
return {
|
||||
/**
|
||||
* The player's guessed words so far
|
||||
*/
|
||||
guesses: game.guesses,
|
||||
|
||||
/**
|
||||
* An array of strings like '__x_c' corresponding to the guesses, where 'x' means
|
||||
* an exact match, and 'c' means a close match (right letter, wrong place)
|
||||
*/
|
||||
answers: game.answers,
|
||||
|
||||
/**
|
||||
* The correct answer, revealed if the game is over
|
||||
*/
|
||||
answer: game.answers.length >= 6 ? game.answer : null
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
/**
|
||||
* Modify game state in reaction to a keypress. If client-side JavaScript
|
||||
* is available, this will happen in the browser instead of here
|
||||
*/
|
||||
update: async ({ request, cookies }) => {
|
||||
const game = new Game(cookies.get('sverdle'));
|
||||
|
||||
const data = await request.formData();
|
||||
const key = data.get('key');
|
||||
|
||||
const i = game.answers.length;
|
||||
|
||||
if (key === 'backspace') {
|
||||
game.guesses[i] = game.guesses[i].slice(0, -1);
|
||||
} else {
|
||||
game.guesses[i] += key;
|
||||
}
|
||||
|
||||
cookies.set('sverdle', game.toString());
|
||||
},
|
||||
|
||||
/**
|
||||
* Modify game state in reaction to a guessed word. This logic always runs on
|
||||
* the server, so that people can't cheat by peeking at the JavaScript
|
||||
*/
|
||||
enter: async ({ request, cookies }) => {
|
||||
const game = new Game(cookies.get('sverdle'));
|
||||
|
||||
const data = await request.formData();
|
||||
const guess = data.getAll('guess') as string[];
|
||||
|
||||
if (!game.enter(guess)) {
|
||||
return invalid(400, { badGuess: true });
|
||||
}
|
||||
|
||||
cookies.set('sverdle', game.toString());
|
||||
},
|
||||
|
||||
restart: async ({ cookies }) => {
|
||||
cookies.delete('sverdle');
|
||||
}
|
||||
};
|
||||
|
||||
class Game {
|
||||
index: number;
|
||||
guesses: string[];
|
||||
answers: string[];
|
||||
answer: string;
|
||||
|
||||
/**
|
||||
* Create a game object from the player's cookie, or initialise a new game
|
||||
*/
|
||||
constructor(serialized: string | undefined) {
|
||||
if (serialized) {
|
||||
const [index, guesses, answers] = serialized.split('-');
|
||||
|
||||
this.index = +index;
|
||||
this.guesses = guesses ? guesses.split(' ') : [];
|
||||
this.answers = answers ? answers.split(' ') : [];
|
||||
} else {
|
||||
this.index = Math.floor(Math.random() * words.length);
|
||||
this.guesses = ['', '', '', '', '', ''];
|
||||
this.answers = [] ;
|
||||
}
|
||||
|
||||
this.answer = words[this.index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update game state based on a guess of a five-letter word. Returns
|
||||
* true if the guess was valid, false otherwise
|
||||
*/
|
||||
enter(letters: string[]) {
|
||||
const word = letters.join('');
|
||||
const valid = allowed.has(word);
|
||||
|
||||
if (!valid) return false;
|
||||
|
||||
this.guesses[this.answers.length] = word;
|
||||
|
||||
const available = Array.from(this.answer);
|
||||
const answer = Array(5).fill('_');
|
||||
|
||||
// first, find exact matches
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
if (letters[i] === available[i]) {
|
||||
answer[i] = 'x';
|
||||
available[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// then find close matches (this has to happen
|
||||
// in a second step, otherwise an early close
|
||||
// match can prevent a later exact match)
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
if (answer[i] === '_') {
|
||||
const index = available.indexOf(letters[i]);
|
||||
if (index !== -1) {
|
||||
answer[i] = 'c';
|
||||
available[index] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.answers.push(answer.join(''));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize game state so it can be set as a cookie
|
||||
*/
|
||||
toString() {
|
||||
return `${this.index}-${this.guesses.join(' ')}-${this.answers.join(' ')}`;
|
||||
}
|
||||
}
|
||||
@@ -1,388 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { confetti } from '@neoconfetti/svelte';
|
||||
import { applyAction, enhance } from '$app/forms';
|
||||
import type { PageData, ActionData } from './$types';
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
export let form: ActionData;
|
||||
|
||||
/** Whether or not the user has won */
|
||||
$: won = data.answers.at(-1) === 'xxxxx';
|
||||
|
||||
/** The index of the current guess */
|
||||
$: i = won ? -1 : data.answers.length;
|
||||
|
||||
/** Whether the current guess can be submitted */
|
||||
$: submittable = data.guesses[i]?.length === 5;
|
||||
|
||||
/**
|
||||
* A map of classnames for all letters that have been guessed,
|
||||
* used for styling the keyboard
|
||||
*/
|
||||
let classnames: Record<string, 'exact' | 'close' | 'missing'>;
|
||||
|
||||
$: {
|
||||
classnames = {};
|
||||
|
||||
data.answers.forEach((answer, i) => {
|
||||
const guess = data.guesses[i];
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
const letter = guess[i];
|
||||
|
||||
if (answer[i] === 'x') {
|
||||
classnames[letter] = 'exact';
|
||||
} else if (!classnames[letter]) {
|
||||
classnames[letter] = answer[i] === 'c' ? 'close' : 'missing';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the game state without making a trip to the server,
|
||||
* if client-side JavaScript is enabled
|
||||
*/
|
||||
function update(event: MouseEvent) {
|
||||
const guess = data.guesses[i];
|
||||
const key = (event.target as HTMLButtonElement).getAttribute(
|
||||
'data-key'
|
||||
);
|
||||
|
||||
if (key === 'backspace') {
|
||||
data.guesses[i] = guess.slice(0, -1);
|
||||
if (form?.badGuess) form.badGuess = false;
|
||||
} else if (guess.length < 5) {
|
||||
data.guesses[i] += key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger form logic in response to a keydown event, so that
|
||||
* desktop users can use the keyboard to play the game
|
||||
*/
|
||||
function keydown(event: KeyboardEvent) {
|
||||
if (event.metaKey) return;
|
||||
|
||||
document
|
||||
.querySelector(`[data-key="${event.key}" i]`)
|
||||
?.dispatchEvent(new MouseEvent('click', { cancelable: true }));
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={keydown} />
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="?/enter"
|
||||
use:enhance={() => {
|
||||
// prevent default callback from resetting the form
|
||||
return async ({ result }) => {
|
||||
if (result.type === 'success') {
|
||||
await invalidateAll();
|
||||
}
|
||||
await applyAction(result);
|
||||
};
|
||||
}}
|
||||
>
|
||||
<a class="how-to-play" href="/sverdle/how-to-play">How to play</a>
|
||||
|
||||
<div class="grid" class:playing={!won} class:bad-guess={form?.badGuess}>
|
||||
{#each Array(6) as _, row}
|
||||
{@const current = row === i}
|
||||
|
||||
<div class="row" class:current>
|
||||
{#each Array(5) as _, column}
|
||||
{@const answer = data.answers[row]?.[column]}
|
||||
|
||||
<input
|
||||
name="guess"
|
||||
disabled={!current}
|
||||
readonly
|
||||
class:exact={answer === 'x'}
|
||||
class:close={answer === 'c'}
|
||||
aria-selected={current && column === data.guesses[row].length}
|
||||
value={data.guesses[row]?.[column] ?? ''}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
{#if won || data.answers.length >= 6}
|
||||
{#if !won && data.answer}
|
||||
<p>the answer was "{data.answer}"</p>
|
||||
{/if}
|
||||
<button data-key="enter" aria-selected="true" class="restart" formaction="?/restart">
|
||||
{won ? 'you won :)' : `game over :(`} play again?
|
||||
</button>
|
||||
{:else}
|
||||
<div class="keyboard">
|
||||
<button data-key="enter" aria-selected={submittable} disabled={!submittable}>enter</button>
|
||||
|
||||
<button
|
||||
on:click|preventDefault={update}
|
||||
data-key="backspace"
|
||||
formaction="?/update"
|
||||
name="key"
|
||||
value="backspace"
|
||||
>
|
||||
back
|
||||
</button>
|
||||
|
||||
{#each ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'] as row}
|
||||
<div class="row">
|
||||
{#each row as letter}
|
||||
<button
|
||||
on:click|preventDefault={update}
|
||||
data-key={letter}
|
||||
class={classnames[letter]}
|
||||
disabled={data.guesses[i].length === 5}
|
||||
formaction="?/update"
|
||||
name="key"
|
||||
value={letter}
|
||||
>
|
||||
{letter}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{#if won}
|
||||
<div
|
||||
style="position: absolute; left: 50%; top: 30%"
|
||||
use:confetti={{
|
||||
force: 0.7,
|
||||
stageWidth: window.innerWidth,
|
||||
stageHeight: window.innerHeight,
|
||||
colors: ['#ff3e00', '#40b3ff', '#676778']
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
form {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.how-to-play {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.how-to-play::before {
|
||||
content: 'i';
|
||||
display: inline-block;
|
||||
font-size: 0.8em;
|
||||
font-weight: 900;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
padding: 0.2em;
|
||||
line-height: 1;
|
||||
border: 1.5px solid var(--color-text);
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
margin: 0 0.5em 0 0;
|
||||
position: relative;
|
||||
top: -0.05em;
|
||||
}
|
||||
|
||||
.grid {
|
||||
--width: min(100vw, 40vh, 380px);
|
||||
max-width: var(--width);
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.grid .row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-gap: 0.2rem;
|
||||
margin: 0 0 0.2rem 0;
|
||||
}
|
||||
|
||||
.grid.bad-guess .row.current {
|
||||
animation: wiggle 0.5s;
|
||||
}
|
||||
|
||||
.grid.playing .row.current {
|
||||
filter: drop-shadow(3px 3px 10px var(--color-bg-0));
|
||||
}
|
||||
|
||||
input {
|
||||
aspect-ratio: 1;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
text-transform: lowercase;
|
||||
border: none;
|
||||
font-size: calc(0.08 * var(--width));
|
||||
border-radius: 2px;
|
||||
background: white;
|
||||
margin: 0;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
input:disabled:not(.exact):not(.close) {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
input.exact {
|
||||
background: var(--color-theme-2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
input.close {
|
||||
border: 2px solid var(--color-theme-2);
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[aria-selected='true'] {
|
||||
outline: 2px solid var(--color-theme-1);
|
||||
}
|
||||
|
||||
input:not(:disabled)::selection {
|
||||
background: transparent;
|
||||
color: var(--color-theme-1);
|
||||
}
|
||||
|
||||
.controls {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
height: min(18vh, 10rem);
|
||||
}
|
||||
|
||||
.keyboard {
|
||||
--gap: 0.2rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.keyboard .row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.2rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.keyboard button,
|
||||
.keyboard button:disabled {
|
||||
--size: min(8vw, 4vh, 40px);
|
||||
background-color: white;
|
||||
color: black;
|
||||
width: var(--size);
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
font-size: calc(var(--size) * 0.5);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.keyboard button.exact {
|
||||
background: var(--color-theme-2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.keyboard button.missing {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.keyboard button.close {
|
||||
border: 2px solid var(--color-theme-2);
|
||||
}
|
||||
|
||||
.keyboard button:focus {
|
||||
background: var(--color-theme-1);
|
||||
color: white;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.keyboard button[data-key='enter'],
|
||||
.keyboard button[data-key='backspace'] {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: calc(1.5 * var(--size));
|
||||
height: calc(1 / 3 * (100% - 2 * var(--gap)));
|
||||
text-transform: uppercase;
|
||||
font-size: calc(0.3 * var(--size));
|
||||
padding-top: calc(0.15 * var(--size));
|
||||
}
|
||||
|
||||
.keyboard button[data-key='enter'] {
|
||||
right: calc(50% + 3.5 * var(--size) + 0.8rem);
|
||||
}
|
||||
|
||||
.keyboard button[data-key='backspace'] {
|
||||
left: calc(50% + 3.5 * var(--size) + 0.8rem);
|
||||
}
|
||||
|
||||
.keyboard button[data-key='enter']:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.restart {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.restart:focus,
|
||||
.restart:hover {
|
||||
background: var(--color-theme-1);
|
||||
color: white;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@keyframes wiggle {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
10% {
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
30% {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-6px);
|
||||
}
|
||||
70% {
|
||||
transform: translateX(+4px);
|
||||
}
|
||||
90% {
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,90 +0,0 @@
|
||||
<div class="text-column">
|
||||
<h1>How to play Sverdle</h1>
|
||||
|
||||
<p>
|
||||
Sverdle is a clone of <a href="https://www.nytimes.com/games/wordle/index.html">Wordle</a>, the
|
||||
word guessing game. To play, enter a five-letter English word. For example:
|
||||
</p>
|
||||
|
||||
<div class="example">
|
||||
<span class="close">r</span>
|
||||
<span class="missing">i</span>
|
||||
<span class="close">t</span>
|
||||
<span class="missing">z</span>
|
||||
<span class="exact">y</span>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The <span class="exact">y</span> is in the right place. <span class="close">r</span> and
|
||||
<span class="close">t</span>
|
||||
are the right letters, but in the wrong place. The other letters are wrong, and can be discarded.
|
||||
Let's make another guess:
|
||||
</p>
|
||||
|
||||
<div class="example">
|
||||
<span class="exact">p</span>
|
||||
<span class="exact">a</span>
|
||||
<span class="exact">r</span>
|
||||
<span class="exact">t</span>
|
||||
<span class="exact">y</span>
|
||||
</div>
|
||||
|
||||
<p>This time we guessed right! You have <strong>six</strong> guesses to get the word.</p>
|
||||
|
||||
<p>
|
||||
Unlike the original Wordle, Sverdle runs on the server instead of in the browser, making it
|
||||
impossible to cheat. It uses <code><form></code> and cookies to submit data, meaning you can
|
||||
even play with JavaScript disabled!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
span {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 0.8em;
|
||||
width: 2.4em;
|
||||
height: 2.4em;
|
||||
background-color: white;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
border-width: 2px;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.missing {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.close {
|
||||
border-style: solid;
|
||||
border-color: var(--color-theme-2);
|
||||
}
|
||||
|
||||
.exact {
|
||||
background: var(--color-theme-2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.example {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
margin: 1rem 0;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.example span {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
p span {
|
||||
position: relative;
|
||||
border-width: 1px;
|
||||
border-radius: 1px;
|
||||
font-size: 0.4em;
|
||||
transform: scale(2) translate(0, -10%);
|
||||
margin: 0 1em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +0,0 @@
|
||||
import { dev } from '$app/environment';
|
||||
|
||||
// we don't need any JS on this page, though we'll load
|
||||
// it in dev so that we get hot module replacement
|
||||
export const csr = dev;
|
||||
|
||||
// since there's no dynamic data here, we can prerender
|
||||
// it so that it gets served as a static asset in production
|
||||
export const prerender = true;
|
||||
File diff suppressed because it is too large
Load Diff
Generated
+13
@@ -6,6 +6,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-vue": "file:../../packages/overlayscrollbars-vue/dist",
|
||||
"vue": "^3.2.38"
|
||||
},
|
||||
@@ -20,6 +21,7 @@
|
||||
}
|
||||
},
|
||||
"../../packages/overlayscrollbars-vue/dist": {
|
||||
"name": "overlayscrollbars-vue",
|
||||
"version": "0.4.0",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
@@ -27,6 +29,10 @@
|
||||
"vue": "^3.2.25"
|
||||
}
|
||||
},
|
||||
"../../packages/overlayscrollbars/dist": {
|
||||
"version": "2.0.0-beta.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||
@@ -1488,6 +1494,10 @@
|
||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/overlayscrollbars": {
|
||||
"resolved": "../../packages/overlayscrollbars/dist",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/overlayscrollbars-vue": {
|
||||
"resolved": "../../packages/overlayscrollbars-vue/dist",
|
||||
"link": true
|
||||
@@ -2745,6 +2755,9 @@
|
||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
|
||||
"dev": true
|
||||
},
|
||||
"overlayscrollbars": {
|
||||
"version": "file:../../packages/overlayscrollbars/dist"
|
||||
},
|
||||
"overlayscrollbars-vue": {
|
||||
"version": "file:../../packages/overlayscrollbars-vue/dist",
|
||||
"requires": {}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"overlayscrollbars": "file:../../packages/overlayscrollbars/dist",
|
||||
"overlayscrollbars-vue": "file:../../packages/overlayscrollbars-vue/dist",
|
||||
"vue": "^3.2.38"
|
||||
},
|
||||
|
||||
+10
-41
@@ -1,47 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import TheWelcome from './components/TheWelcome.vue';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
|
||||
import type { PartialOptions } from 'overlayscrollbars';
|
||||
|
||||
const options: PartialOptions = {
|
||||
scrollbars: {
|
||||
theme: 'os-theme-light',
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
|
||||
|
||||
<div class="wrapper">
|
||||
<OverlayScrollbarsComponent />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<TheWelcome />
|
||||
</main>
|
||||
<OverlayScrollbarsComponent style="height: 222px; width: 222px" :options="options">
|
||||
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="333" height="333" />
|
||||
</OverlayScrollbarsComponent>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
header {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
padding-right: calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 2rem 0 0;
|
||||
}
|
||||
|
||||
header .wrapper {
|
||||
display: flex;
|
||||
place-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
@import "./base.css";
|
||||
@import './base.css';
|
||||
|
||||
body,
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
|
||||
font-weight: normal;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
a,
|
||||
@@ -20,16 +19,3 @@ a,
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
msg: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="greetings">
|
||||
<h1 class="green">{{ msg }}</h1>
|
||||
<h3>
|
||||
You’ve successfully created a project with
|
||||
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 2.6rem;
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,86 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import WelcomeItem from './WelcomeItem.vue'
|
||||
import DocumentationIcon from './icons/IconDocumentation.vue'
|
||||
import ToolingIcon from './icons/IconTooling.vue'
|
||||
import EcosystemIcon from './icons/IconEcosystem.vue'
|
||||
import CommunityIcon from './icons/IconCommunity.vue'
|
||||
import SupportIcon from './icons/IconSupport.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<DocumentationIcon />
|
||||
</template>
|
||||
<template #heading>Documentation</template>
|
||||
|
||||
Vue’s
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
|
||||
provides you with all information you need to get started.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<ToolingIcon />
|
||||
</template>
|
||||
<template #heading>Tooling</template>
|
||||
|
||||
This project is served and bundled with
|
||||
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
|
||||
recommended IDE setup is
|
||||
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
|
||||
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
|
||||
you need to test your components and web pages, check out
|
||||
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
|
||||
<a href="https://on.cypress.io/component" target="_blank">Cypress Component Testing</a>.
|
||||
|
||||
<br />
|
||||
|
||||
More instructions are available in <code>README.md</code>.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<EcosystemIcon />
|
||||
</template>
|
||||
<template #heading>Ecosystem</template>
|
||||
|
||||
Get official tools and libraries for your project:
|
||||
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
|
||||
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
|
||||
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
|
||||
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
|
||||
you need more resources, we suggest paying
|
||||
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
|
||||
a visit.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<CommunityIcon />
|
||||
</template>
|
||||
<template #heading>Community</template>
|
||||
|
||||
Got stuck? Ask your question on
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
|
||||
Discord server, or
|
||||
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
|
||||
>StackOverflow</a
|
||||
>. You should also subscribe to
|
||||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
|
||||
the official
|
||||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
|
||||
twitter account for latest news in the Vue world.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<SupportIcon />
|
||||
</template>
|
||||
<template #heading>Support Vue</template>
|
||||
|
||||
As an independent project, Vue relies on community backing for its sustainability. You can help
|
||||
us by
|
||||
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
|
||||
</WelcomeItem>
|
||||
</template>
|
||||
@@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div class="item">
|
||||
<i>
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<div class="details">
|
||||
<h3>
|
||||
<slot name="heading"></slot>
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
place-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.item {
|
||||
margin-top: 0;
|
||||
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
i {
|
||||
top: calc(50% - 25px);
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-background);
|
||||
border-radius: 8px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.item:before {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:first-of-type:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
class="iconify iconify--mdi"
|
||||
width="24"
|
||||
height="24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ module.exports = (resolve, options) => {
|
||||
rollupAlias(resolve, alias),
|
||||
rollupScss(
|
||||
resolve,
|
||||
sourcemap && !minified,
|
||||
false && sourcemap && !minified,
|
||||
extractStyles,
|
||||
path.resolve(stylesPath, cssFilename),
|
||||
banner,
|
||||
|
||||
Reference in New Issue
Block a user