mirror of
https://github.com/anatolykopyl/variants.git
synced 2026-03-26 04:44:37 +00:00
Initial commit
This commit is contained in:
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# VARIANTS
|
||||||
|
|
||||||
|
Веб приложение для распределения вариантов и для деления на бригады
|
||||||
2722
package-lock.json
generated
Normal file
2722
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
package.json
Normal file
37
package.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "variancc",
|
||||||
|
"description": "Variancc",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "sapper dev",
|
||||||
|
"build": "sapper build --legacy",
|
||||||
|
"export": "sapper export --legacy",
|
||||||
|
"start": "node __sapper__/build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"compression": "^1.7.1",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"mongodb": "^3.6.2",
|
||||||
|
"polka": "next",
|
||||||
|
"query-string": "^6.13.2",
|
||||||
|
"sirv": "^1.0.0",
|
||||||
|
"uuid": "^8.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sapper": "^0.28.0",
|
||||||
|
"svelte": "^3.17.3",
|
||||||
|
"@babel/core": "^7.0.0",
|
||||||
|
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||||
|
"@babel/preset-env": "^7.0.0",
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"@rollup/plugin-babel": "^5.0.0",
|
||||||
|
"@rollup/plugin-commonjs": "^14.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^8.0.0",
|
||||||
|
"@rollup/plugin-replace": "^2.2.0",
|
||||||
|
"rollup": "^2.3.4",
|
||||||
|
"rollup-plugin-svelte": "^6.0.0",
|
||||||
|
"rollup-plugin-terser": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
105
rollup.config.js
Normal file
105
rollup.config.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import replace from '@rollup/plugin-replace';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import svelte from 'rollup-plugin-svelte';
|
||||||
|
import babel from '@rollup/plugin-babel';
|
||||||
|
import { terser } from 'rollup-plugin-terser';
|
||||||
|
import config from 'sapper/config/rollup.js';
|
||||||
|
import pkg from './package.json';
|
||||||
|
|
||||||
|
const mode = process.env.NODE_ENV;
|
||||||
|
const dev = mode === 'development';
|
||||||
|
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
|
||||||
|
|
||||||
|
const onwarn = (warning, onwarn) =>
|
||||||
|
(warning.code === 'MISSING_EXPORT' && /'preload'/.test(warning.message)) ||
|
||||||
|
(warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) ||
|
||||||
|
onwarn(warning);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
client: {
|
||||||
|
input: config.client.input(),
|
||||||
|
output: config.client.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
dev,
|
||||||
|
hydratable: true,
|
||||||
|
emitCss: true
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
browser: true,
|
||||||
|
dedupe: ['svelte']
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
|
||||||
|
legacy && babel({
|
||||||
|
extensions: ['.js', '.mjs', '.html', '.svelte'],
|
||||||
|
babelHelpers: 'runtime',
|
||||||
|
exclude: ['node_modules/@babel/**'],
|
||||||
|
presets: [
|
||||||
|
['@babel/preset-env', {
|
||||||
|
targets: '> 0.25%, not dead'
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-syntax-dynamic-import',
|
||||||
|
['@babel/plugin-transform-runtime', {
|
||||||
|
useESModules: true
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
!dev && terser({
|
||||||
|
module: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
|
preserveEntrySignatures: false,
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
|
||||||
|
server: {
|
||||||
|
input: config.server.input(),
|
||||||
|
output: config.server.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.browser': false,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
generate: 'ssr',
|
||||||
|
hydratable: true,
|
||||||
|
dev
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
dedupe: ['svelte']
|
||||||
|
}),
|
||||||
|
commonjs()
|
||||||
|
],
|
||||||
|
external: Object.keys(pkg.dependencies).concat(require('module').builtinModules),
|
||||||
|
|
||||||
|
preserveEntrySignatures: 'strict',
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceworker: {
|
||||||
|
input: config.serviceworker.input(),
|
||||||
|
output: config.serviceworker.output(),
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
replace({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
!dev && terser()
|
||||||
|
],
|
||||||
|
|
||||||
|
preserveEntrySignatures: false,
|
||||||
|
onwarn,
|
||||||
|
}
|
||||||
|
};
|
||||||
5
src/client.js
Normal file
5
src/client.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import * as sapper from '@sapper/app';
|
||||||
|
|
||||||
|
sapper.start({
|
||||||
|
target: document.querySelector('#sapper')
|
||||||
|
});
|
||||||
40
src/routes/_error.svelte
Normal file
40
src/routes/_error.svelte
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<script>
|
||||||
|
export let status;
|
||||||
|
export let error;
|
||||||
|
|
||||||
|
const dev = process.env.NODE_ENV === 'development';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1, p {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.8em;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0 0 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 480px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{status}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<h1>{status}</h1>
|
||||||
|
|
||||||
|
<p>{error.message}</p>
|
||||||
|
|
||||||
|
{#if dev && error.stack}
|
||||||
|
<pre>{error.stack}</pre>
|
||||||
|
{/if}
|
||||||
3
src/routes/_layout.svelte
Normal file
3
src/routes/_layout.svelte
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<main>
|
||||||
|
<slot></slot>
|
||||||
|
</main>
|
||||||
164
src/routes/index.svelte
Normal file
164
src/routes/index.svelte
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<script>
|
||||||
|
let groupTask = false;
|
||||||
|
let name = "";
|
||||||
|
let memberCount = 10;
|
||||||
|
|
||||||
|
function createRoom() {
|
||||||
|
const url=`http://localhost:3000/api/create/?g=${groupTask}&n=${name}&c=${memberCount}`;
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Varian.cc</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<greeting>
|
||||||
|
<h1>varian.cc</h1>
|
||||||
|
<div class="startbtns">
|
||||||
|
<div>
|
||||||
|
<h2>Создать работу</h2>
|
||||||
|
<div class="inputs">
|
||||||
|
<div class="toggle">
|
||||||
|
По вариантам
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" bind:checked={groupTask}>
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
По бригадам
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Количество {#if groupTask}бригад{:else}вариантов{/if}:
|
||||||
|
<input type="number" id="varCount" name="варианты" min="2" max="50" bind:value={memberCount}>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Название работы:<br>
|
||||||
|
<input type="text" size="45" placeholder="Лабораторная работа по физике №3" bind:value={name}>
|
||||||
|
</div>
|
||||||
|
<input type="button" value="Создать" on:click={createRoom}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Присоедениться к работе</h2>
|
||||||
|
<div class="inputs">
|
||||||
|
<div>
|
||||||
|
Код подключения:<br>
|
||||||
|
<input type="text" size="45" placeholder="43d0505c-d695-4323-9140-5d7744ec95e7">
|
||||||
|
</div>
|
||||||
|
<input type="button" value="Подключиться" on:click={connect}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</greeting>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
greeting {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.startbtns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.startbtns > div {
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: lightgrey 0px 5px 20px;
|
||||||
|
width: 30vw;
|
||||||
|
height: 30vw;
|
||||||
|
padding: 2vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: xx-large;
|
||||||
|
font-weight: 100;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
padding-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputs {
|
||||||
|
display: flex;
|
||||||
|
height: 75%;
|
||||||
|
margin-left: 5%;
|
||||||
|
margin-right: 5%;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 60px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #2196F3;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
left: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
background-color: white;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: #f57323;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + .slider {
|
||||||
|
box-shadow: 0 0 1px #f57323;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
-webkit-transform: translateX(26px);
|
||||||
|
-ms-transform: translateX(26px);
|
||||||
|
transform: translateX(26px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rounded sliders */
|
||||||
|
.slider.round {
|
||||||
|
border-radius: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round:before {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
100
src/routes/room.svelte
Normal file
100
src/routes/room.svelte
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<script>
|
||||||
|
import queryString from "query-string";
|
||||||
|
|
||||||
|
let parsed = {};
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
parsed = queryString.parse(window.location.search);
|
||||||
|
}
|
||||||
|
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let room;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
var url = `http://localhost:3000/api/join/?id=${parsed.id}`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
room = await res.json();
|
||||||
|
console.log(room);
|
||||||
|
});
|
||||||
|
|
||||||
|
function selectVar(selected) {
|
||||||
|
if (!room.teams[selected]) {
|
||||||
|
room.teams[selected] = [];
|
||||||
|
}
|
||||||
|
room.teams[selected][room.teams[selected].length] = "Толя";
|
||||||
|
console.log(room.teams[selected]);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title></title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<list>
|
||||||
|
{#if room}
|
||||||
|
<h1>{room.name}</h1>
|
||||||
|
<ol>
|
||||||
|
{#each room.teams as _, i}
|
||||||
|
<li class={room.group==="true" ? "group" : "individual"} on:click={() => selectVar(i)}>
|
||||||
|
{#each room.teams[i] as name}
|
||||||
|
<span class="name">{name}</span>
|
||||||
|
{/each}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
{:else}
|
||||||
|
Loading...
|
||||||
|
{/if}
|
||||||
|
</list>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
list {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
width: 50%;
|
||||||
|
margin: auto;
|
||||||
|
list-style: none;
|
||||||
|
counter-reset: item;
|
||||||
|
font-size: larger;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: solid lightblue 1px;
|
||||||
|
counter-increment: item;
|
||||||
|
padding: 6px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
background-color: lightcoral;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 3px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:before {
|
||||||
|
margin-right: 10px;
|
||||||
|
content: counter(item);
|
||||||
|
border-radius: 100%;
|
||||||
|
color: white;
|
||||||
|
width: 1.2em;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.individual:before {
|
||||||
|
background-color: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group:before {
|
||||||
|
background-color: #f57323;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
68
src/server.js
Normal file
68
src/server.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import sirv from 'sirv';
|
||||||
|
import polka from 'polka';
|
||||||
|
import compression from 'compression';
|
||||||
|
const dotenv = require('dotenv');
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import * as sapper from '@sapper/server';
|
||||||
|
const MongoClient = require('mongodb');
|
||||||
|
|
||||||
|
const { PORT, NODE_ENV } = process.env;
|
||||||
|
const dev = NODE_ENV === 'development';
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
const app = polka();
|
||||||
|
|
||||||
|
MongoClient.connect(process.env.DB_CONNECTION, { useUnifiedTopology: true })
|
||||||
|
.then(client => {
|
||||||
|
console.log('Connected to Database')
|
||||||
|
const db = client.db('variants');
|
||||||
|
const rooms = db.collection('rooms');
|
||||||
|
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
res.redirect = location => {
|
||||||
|
let str = `Redirecting to ${location}`;
|
||||||
|
res.writeHead(302, {
|
||||||
|
Location: location,
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
'Content-Length': str.length,
|
||||||
|
});
|
||||||
|
res.end(str);
|
||||||
|
};
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/create/', (req, res) => {
|
||||||
|
console.log(req.query);
|
||||||
|
const id = uuidv4();
|
||||||
|
let teams = [];
|
||||||
|
for (let i = 0; i < req.query.c; i++) {
|
||||||
|
teams[i] = [];
|
||||||
|
}
|
||||||
|
rooms.insertOne({
|
||||||
|
"id": id,
|
||||||
|
"name": req.query.n,
|
||||||
|
"group": req.query.g,
|
||||||
|
"memberCount": req.query.c,
|
||||||
|
"teams": teams
|
||||||
|
});
|
||||||
|
|
||||||
|
res.redirect(`http://localhost:3000/room/?id=${id}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/join/', (req, res) => {
|
||||||
|
rooms.findOne({ "id": req.query.id }).then(room => {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
res.write(JSON.stringify(room));
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
compression({ threshold: 0 }),
|
||||||
|
sirv('static', { dev }),
|
||||||
|
sapper.middleware()
|
||||||
|
)
|
||||||
|
.listen(PORT, err => {
|
||||||
|
if (err) console.log('error', err);
|
||||||
|
});
|
||||||
|
});
|
||||||
82
src/service-worker.js
Normal file
82
src/service-worker.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { timestamp, files, shell, routes } from '@sapper/service-worker';
|
||||||
|
|
||||||
|
const ASSETS = `cache${timestamp}`;
|
||||||
|
|
||||||
|
// `shell` is an array of all the files generated by the bundler,
|
||||||
|
// `files` is an array of everything in the `static` directory
|
||||||
|
const to_cache = shell.concat(files);
|
||||||
|
const cached = new Set(to_cache);
|
||||||
|
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches
|
||||||
|
.open(ASSETS)
|
||||||
|
.then(cache => cache.addAll(to_cache))
|
||||||
|
.then(() => {
|
||||||
|
self.skipWaiting();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then(async keys => {
|
||||||
|
// delete old caches
|
||||||
|
for (const key of keys) {
|
||||||
|
if (key !== ASSETS) await caches.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.clients.claim();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', event => {
|
||||||
|
if (event.request.method !== 'GET' || event.request.headers.has('range')) return;
|
||||||
|
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
|
||||||
|
// don't try to handle e.g. data: URIs
|
||||||
|
if (!url.protocol.startsWith('http')) return;
|
||||||
|
|
||||||
|
// ignore dev server requests
|
||||||
|
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||||
|
|
||||||
|
// always serve static files and bundler-generated assets from cache
|
||||||
|
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||||
|
event.respondWith(caches.match(event.request));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for pages, you might want to serve a shell `service-worker-index.html` file,
|
||||||
|
// which Sapper has generated for you. It's not right for every
|
||||||
|
// app, but if it's right for yours then uncomment this section
|
||||||
|
/*
|
||||||
|
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||||
|
event.respondWith(caches.match('/service-worker-index.html'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (event.request.cache === 'only-if-cached') return;
|
||||||
|
|
||||||
|
// for everything else, try the network first, falling back to
|
||||||
|
// cache if the user is offline. (If the pages never change, you
|
||||||
|
// might prefer a cache-first approach to a network-first one.)
|
||||||
|
event.respondWith(
|
||||||
|
caches
|
||||||
|
.open(`offline${timestamp}`)
|
||||||
|
.then(async cache => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(event.request);
|
||||||
|
cache.put(event.request, response.clone());
|
||||||
|
return response;
|
||||||
|
} catch(err) {
|
||||||
|
const response = await cache.match(event.request);
|
||||||
|
if (response) return response;
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
33
src/template.html
Normal file
33
src/template.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<meta name="theme-color" content="#333333">
|
||||||
|
|
||||||
|
%sapper.base%
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="global.css">
|
||||||
|
<link rel="manifest" href="manifest.json" crossorigin="use-credentials">
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png">
|
||||||
|
|
||||||
|
<!-- Sapper creates a <script> tag containing `src/client.js`
|
||||||
|
and anything else it needs to hydrate the app and
|
||||||
|
initialise the router -->
|
||||||
|
%sapper.scripts%
|
||||||
|
|
||||||
|
<!-- Sapper generates a <style> tag containing critical CSS
|
||||||
|
for the current page. CSS for the rest of the app is
|
||||||
|
lazily loaded when it precaches secondary pages -->
|
||||||
|
%sapper.styles%
|
||||||
|
|
||||||
|
<!-- This contains the contents of the <svelte:head> component, if
|
||||||
|
the current page has one -->
|
||||||
|
%sapper.head%
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- The application will be rendered inside this element,
|
||||||
|
because `src/client.js` references it -->
|
||||||
|
<div id="sapper">%sapper.html%</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
63
static/global.css
Normal file
63
static/global.css
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
html, body {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: rgb(0,100,200);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: rgb(0,80,160);
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, button, select, textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
-webkit-padding: 0.4em 0;
|
||||||
|
padding: 0.4em;
|
||||||
|
margin: 0 0 0.5em 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:disabled {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: #333;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled):active {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus {
|
||||||
|
border-color: #666;
|
||||||
|
}
|
||||||
BIN
static/logo-192.png
Normal file
BIN
static/logo-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
static/logo-512.png
Normal file
BIN
static/logo-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
20
static/manifest.json
Normal file
20
static/manifest.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"theme_color": "#333333",
|
||||||
|
"name": "TODO",
|
||||||
|
"short_name": "TODO",
|
||||||
|
"display": "minimal-ui",
|
||||||
|
"start_url": "/",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "logo-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user