Initial commit, basic pages and sessions.
This commit is contained in:
commit
bc9fec207b
|
@ -0,0 +1,14 @@
|
|||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
[*.js]
|
||||
charset = utf-8
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": ["airbnb-base", "plugin:vue/recommended"],
|
||||
"parserOptions": {
|
||||
"parser": "@babel/eslint-parser",
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module",
|
||||
"requireConfigFile": false
|
||||
},
|
||||
"rules": {
|
||||
"indent": ["error", "tab"],
|
||||
"no-tabs": "off",
|
||||
"no-unused-vars": ["error", {"argsIgnorePattern": "^_"}],
|
||||
"no-console": 0,
|
||||
"template-curly-spacing": "off",
|
||||
"import/prefer-default-export": 0,
|
||||
"max-len": 0,
|
||||
"vue/no-v-html": 0,
|
||||
"vue/html-indent": ["error", "tab"],
|
||||
"vue/multiline-html-element-content-newline": 0,
|
||||
"vue/singleline-html-element-content-newline": 0,
|
||||
"vue/multi-word-component-names": 0,
|
||||
"no-param-reassign": ["error", {
|
||||
"props": true,
|
||||
"ignorePropertyModificationsFor": ["state", "acc"]
|
||||
}]
|
||||
},
|
||||
"globals": {
|
||||
"CONFIG": "readonly",
|
||||
"CLIENT_VERSION": "readonly"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
node_modules/
|
||||
dist/
|
||||
config/
|
||||
!config/default.js
|
||||
assets/js/config/
|
||||
!assets/js/config/default.js
|
|
@ -0,0 +1,48 @@
|
|||
.form {
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
.input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.form-column {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
margin-bottom: .5rem;
|
||||
justify-content: flex-end;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.form-heading {
|
||||
color: var(--primary-light-10);
|
||||
margin: 0 0 .75rem 0;
|
||||
}
|
||||
|
||||
.form-error {
|
||||
background: var(--error);
|
||||
color: var(--text-light);
|
||||
padding: 1rem;
|
||||
border-radius: .25rem;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
.input {
|
||||
padding: .5rem .75rem;
|
||||
font-size: 1rem;
|
||||
flex-basis: 0;
|
||||
border: solid 1px var(--grey-light-30);
|
||||
border-radius: .25rem;
|
||||
font: inherit;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-light-30);
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: .5rem 1rem;
|
||||
border: none;
|
||||
border-radius: .25rem;
|
||||
background: var(--grey-light-30);
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.button-submit {
|
||||
background: var(--primary-light-30);
|
||||
color: var(--text-light);
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--shadow-weak-10);
|
||||
}
|
||||
}
|
||||
|
||||
.radio {
|
||||
margin: 0 .5rem 0 0;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
.markdown-body {
|
||||
margin: 0 auto;
|
||||
max-width: 50rem;
|
||||
flex-grow: 1;
|
||||
padding: 1rem;
|
||||
line-height: 1.5;
|
||||
text-align: justify;
|
||||
|
||||
& h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
& h2 {
|
||||
color: var(--primary);
|
||||
margin: 1rem 0 0 0;
|
||||
}
|
||||
|
||||
& p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
.noselect {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.nolist {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.nolink {
|
||||
display: inline-block;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nobar {
|
||||
scrollbar-width: none;
|
||||
-mis-overflow-style: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
@import 'theme';
|
||||
@import 'states';
|
||||
@import 'inputs';
|
||||
@import 'forms';
|
||||
@import 'markdown';
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: var(--link);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--primary-light-20);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
:root {
|
||||
--primary: hsl(300, 100%, 30%);
|
||||
--primary-light-10: hsl(300, 50%, 40%);
|
||||
--primary-light-20: hsl(300, 50%, 50%);
|
||||
--primary-light-30: hsl(300, 50%, 60%);
|
||||
|
||||
--grey-dark-40: #222;
|
||||
--grey-dark-30: #444;
|
||||
--grey-dark-20: #666;
|
||||
--grey-dark-10: #888;
|
||||
--grey: #aaa;
|
||||
--grey-light-10: #bbb;
|
||||
--grey-light-20: #ccc;
|
||||
--grey-light-30: #ddd;
|
||||
--grey-light-40: #eee;
|
||||
|
||||
--background-dark-20: #eee;
|
||||
--background-dark-10: #f8f8f8;
|
||||
--background: #fff;
|
||||
|
||||
--shadow-weak-30: rgba(0, 0, 0, .1);
|
||||
--shadow-weak-20: rgba(0, 0, 0, .2);
|
||||
--shadow-weak-10: rgba(0, 0, 0, .35);
|
||||
--shadow: rgba(0, 0, 0, .5);
|
||||
--shadow-strong-10: rgba(0, 0, 0, .6);
|
||||
--shadow-strong-20: rgba(0, 0, 0, .75);
|
||||
--shadow-strong-30: rgba(0, 0, 0, .9);
|
||||
|
||||
--text: #222;
|
||||
--text-light: #fff;
|
||||
|
||||
--link: #48f;
|
||||
--error: #f66;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="22.806mm"
|
||||
height="22.806mm"
|
||||
viewBox="0 0 22.806 22.805999"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
sodipodi:docname="favicon.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.4247457"
|
||||
inkscape:cx="35.024683"
|
||||
inkscape:cy="42.674811"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient2720"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2718" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-81.250065,-117.45377)">
|
||||
<g
|
||||
aria-label="shack"
|
||||
id="text236"
|
||||
style="font-size:35.2777px;font-family:LOVES;-inkscape-font-specification:LOVES;stroke-width:0.264583"
|
||||
transform="translate(1.8428824)">
|
||||
<g
|
||||
id="g2730"
|
||||
style="stroke-width:0.265;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 95.564404,131.63031 -4.478614,-11.07596 -4.788672,11.07596 z m 4.805896,8.62994 h -1.309132 l -3.014451,-7.44139 H 85.780355 l -3.221157,7.44139 h -1.309133 l 9.870176,-22.80648 z"
|
||||
id="path2625"
|
||||
style="fill:#880088;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
style="color:#000000;fill:#880088;fill-opacity:1;-inkscape-stroke:none"
|
||||
d="m 90.289784,134.44531 v 5.81446 h 1 v -4.81446 h 2.726562 v 4.81446 h 1 v -5.81446 z"
|
||||
id="path2716" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,83 @@
|
|||
<svg
|
||||
width="106.43599mm"
|
||||
height="23.46104mm"
|
||||
viewBox="0 0 106.43599 23.46104"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="8.2527944"
|
||||
inkscape:cx="181.87779"
|
||||
inkscape:cy="65.977652"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient2720"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2718" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-40.339649,-117.14372)">
|
||||
<g
|
||||
aria-label="shack"
|
||||
id="text236"
|
||||
style="font-size:35.2777px;font-family:LOVES;-inkscape-font-specification:LOVES;stroke-width:0.264583">
|
||||
<g
|
||||
id="g2730"
|
||||
style="stroke-width:0.265;stroke-dasharray:none">
|
||||
<path
|
||||
d="m 47.488206,140.38083 q -2.170405,0 -4.168556,-0.99907 -1.998151,-1.0163 -2.980001,-3.13503 l 1.102428,-0.46509 q 1.016301,2.15318 3.203932,2.92832 1.412486,0.49954 2.842197,0.49954 2.652718,0 4.530291,-1.48139 1.309133,-1.03352 1.378035,-2.87664 -0.05168,-2.20486 -3.152256,-4.01353 -1.291907,-0.74069 -2.56659,-1.34359 -3.858498,-1.80867 -5.787747,-4.09965 -1.102428,-1.30913 -1.102428,-2.66994 0,-1.87758 1.274682,-3.29006 1.291908,-1.41249 3.634568,-1.94648 0.98185,-0.22393 1.980925,-0.22393 0.740694,0 1.980926,0.20671 1.257457,0.18948 2.721619,1.17133 1.481388,0.98185 2.273758,2.73884 l -1.102428,0.44786 q -1.033527,-2.1704 -3.203932,-2.92832 -1.343584,-0.46509 -2.687168,-0.46509 -2.687169,0 -4.478614,1.53307 -1.188556,1.0163 -1.188556,2.82497 0.120578,1.24023 1.257457,2.37711 1.136879,1.11965 2.53214,1.98093 1.39526,0.84404 2.428787,1.2919 1.360809,0.63734 2.790521,1.49862 1.446937,0.86127 2.497688,2.06705 1.050752,1.20578 1.102428,2.8422 -0.03445,1.99815 -1.446936,3.42786 -1.412486,1.42971 -3.841273,1.92925 -0.895723,0.17225 -1.825897,0.17225 z"
|
||||
id="path2621"
|
||||
style="stroke-width:0.265;stroke-dasharray:none" />
|
||||
<path
|
||||
d="m 76.719776,140.26025 h -1.205781 v -10.7659 H 60.510638 v 10.7659 h -1.188555 v -22.77203 h 1.188555 v 10.80035 h 15.003357 v -10.80035 h 1.205781 z"
|
||||
id="path2623"
|
||||
style="stroke-width:0.265;stroke-dasharray:none" />
|
||||
<path
|
||||
d="m 95.564404,131.63031 -4.478614,-11.07596 -4.788672,11.07596 z m 4.805896,8.62994 h -1.309132 l -3.014451,-7.44139 H 85.780355 l -3.221157,7.44139 h -1.309133 l 9.870176,-22.80648 z"
|
||||
id="path2625"
|
||||
style="stroke-width:0.265;stroke-dasharray:none" />
|
||||
<path
|
||||
d="m 114.54684,140.58754 q -3.23838,0 -5.90833,-1.58474 -2.66994,-1.58474 -4.25468,-4.23746 -1.58474,-2.66994 -1.58474,-5.8911 0,-3.23838 1.58474,-5.8911 1.58474,-2.66994 4.25468,-4.25468 2.66995,-1.58474 5.90833,-1.58474 3.41064,0 6.16671,1.73976 2.77329,1.73977 4.28913,4.61642 h -1.42971 q -1.41249,-2.34266 -3.7896,-3.73792 -2.35988,-1.41248 -5.23653,-1.41248 -2.89387,0 -5.27099,1.42971 -2.37711,1.41248 -3.80682,3.80682 -1.41248,2.37711 -1.41248,5.28821 0,2.89387 1.41248,5.28821 1.42971,2.37711 3.80682,3.80682 2.37712,1.41249 5.27099,1.41249 2.66994,0 4.90925,-1.22301 2.25653,-1.22301 3.70347,-3.30728 h 1.48139 q -1.56752,2.61826 -4.22024,4.18578 -2.65271,1.55029 -5.87387,1.55029 z"
|
||||
id="path2627"
|
||||
style="stroke-width:0.265;stroke-dasharray:none" />
|
||||
<path
|
||||
d="m 130.58373,140.60476 v -23.11654 h 1.20578 v 19.03411 l 12.21284,-19.03411 h 1.41248 l -7.83757,12.21284 9.19838,10.55919 h -1.58474 l -8.26821,-9.52566 z"
|
||||
id="path2629"
|
||||
style="stroke-width:0.265;stroke-dasharray:none" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
style="color:#000000;-inkscape-stroke:none"
|
||||
d="m 88.447266,134.44531 v 5.81446 h 1 v -4.81446 h 2.726562 v 4.81446 h 1 v -5.81446 z"
|
||||
id="path2716" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,86 @@
|
|||
const postHeaders = {
|
||||
mode: 'cors',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
function getQuery(data) {
|
||||
if (!data) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `?${new URLSearchParams(data).toString()}`;
|
||||
}
|
||||
|
||||
export async function get(path, query = {}) {
|
||||
const res = await fetch(`${path}${getQuery(query)}`);
|
||||
const body = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
return body;
|
||||
}
|
||||
|
||||
throw new Error(body.message);
|
||||
}
|
||||
|
||||
export async function post(path, data, { query } = {}) {
|
||||
const res = await fetch(`${path}${getQuery(query)}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
...postHeaders,
|
||||
});
|
||||
|
||||
if (res.status === 204) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
return body;
|
||||
}
|
||||
|
||||
throw new Error(body.message);
|
||||
}
|
||||
|
||||
export async function patch(path, data, { query } = {}) {
|
||||
const res = await fetch(`${path}${getQuery(query)}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
...postHeaders,
|
||||
});
|
||||
|
||||
if (res.status === 204) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
return body;
|
||||
}
|
||||
|
||||
throw new Error(body.message);
|
||||
}
|
||||
|
||||
export async function del(path, { data, query } = {}) {
|
||||
const res = await fetch(`${path}${getQuery(query)}`, {
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify(data),
|
||||
...postHeaders,
|
||||
});
|
||||
|
||||
if (res.status === 204) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
return body;
|
||||
}
|
||||
|
||||
throw new Error(body.message);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// centralize navigation to simplify switching between client and server routing
|
||||
export default function navigate(path) {
|
||||
window.location.href = path;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<label class="check-container noselect">
|
||||
<span
|
||||
v-if="label"
|
||||
class="check-label"
|
||||
>{{ label }}</span>
|
||||
|
||||
<input
|
||||
v-show="false"
|
||||
:id="`checkbox-${uid}`"
|
||||
:checked="checked"
|
||||
type="checkbox"
|
||||
class="check-checkbox"
|
||||
@change="$emit('change', $event.target.checked)"
|
||||
>
|
||||
|
||||
<label
|
||||
:for="`checkbox-${uid}`"
|
||||
class="check"
|
||||
/>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['change'],
|
||||
data() {
|
||||
return {
|
||||
uid: nanoid(),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.check-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: .25rem 0;
|
||||
}
|
||||
|
||||
.check {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
border-radius: .25rem;
|
||||
background-color: var(--shadow-weak-20);
|
||||
cursor: pointer;
|
||||
transition: background .15s ease;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: .5rem;
|
||||
height: .3rem;
|
||||
border: solid 2px var(--text-light);
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
margin: -.2rem 0 0 0;
|
||||
transform: rotateZ(-45deg) scaleX(0);
|
||||
transition: transform .15s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.check-cross .check::before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background: url('/img/icons/cross3.svg') no-repeat center/80%;
|
||||
opacity: .15;
|
||||
transition: transform .1s ease;
|
||||
}
|
||||
|
||||
.check-checkbox:checked + .check {
|
||||
background: var(--primary);
|
||||
|
||||
&::after {
|
||||
transform: rotateZ(-45deg) scaleX(1);
|
||||
}
|
||||
|
||||
&::before {
|
||||
transform: scaleX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.check-label {
|
||||
overflow: hidden;
|
||||
text-transform: capitalize;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0 .5rem 0 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,6 @@
|
|||
const config = require('config');
|
||||
|
||||
module.exports = {
|
||||
client: 'pg',
|
||||
connection: config.database,
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
2023-05-26 22:00:04 [32minfo[39m [/home/niels/Projects/shack/src/web/server.js] Server running at :::7477
|
||||
2023-05-26 22:01:41 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:02:51 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:13:32 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:14:07 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:14:56 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:15:07 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:15:33 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:16:20 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:16:33 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 22:23:24 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 23:50:58 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 23:52:16 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 23:59:17 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-26 23:59:40 [32minfo[39m [server] Server running at :::7477
|
|
@ -0,0 +1,42 @@
|
|||
2023-05-27 00:02:12 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 00:02:53 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 00:03:46 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 16:31:42 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:15:42 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:24:43 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:28:55 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:30:14 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:30:48 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:31:08 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:34:32 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 17:53:55 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 22:40:18 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 22:48:27 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:23:00 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:29:39 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:36:51 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:41:25 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:45:38 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:46:09 [32minfo[39m [users] Registered user admin (1, undefined, ::ffff:127.0.0.1)
|
||||
2023-05-27 23:47:00 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:47:51 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:54:47 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:55:07 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:55:23 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:55:31 [33mwarn[39m [error] Failed to fulfill request to /api/users: Username or e-mail already registered
|
||||
2023-05-27 23:55:31 [31merror[39m [error] HttpError: Username or e-mail already registered
|
||||
at createUser (/home/niels/Projects/shack/src/users.js:129:10)
|
||||
at processTicksAndRejections (node:internal/process/task_queues:96:5)
|
||||
at async createUserApi (/home/niels/Projects/shack/src/web/users.js:4:15)
|
||||
2023-05-27 23:56:25 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:57:11 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-27 23:57:17 [33mwarn[39m [error] Failed to fulfill request to /api/users: Username or e-mail already registered
|
||||
2023-05-27 23:57:17 [31merror[39m [error] HttpError: Username or e-mail already registered
|
||||
at createUser (/home/niels/Projects/shack/src/users.js:129:10)
|
||||
at processTicksAndRejections (node:internal/process/task_queues:96:5)
|
||||
at async createUserApi (/home/niels/Projects/shack/src/web/users.js:4:15)
|
||||
2023-05-27 23:58:08 [33mwarn[39m [error] Failed to fulfill request to /api/users: Username or e-mail already registered
|
||||
2023-05-27 23:58:08 [31merror[39m [error] HttpError: Username or e-mail already registered
|
||||
at createUser (/home/niels/Projects/shack/src/users.js:129:10)
|
||||
at processTicksAndRejections (node:internal/process/task_queues:96:5)
|
||||
at async createUserApi (/home/niels/Projects/shack/src/web/users.js:4:15)
|
|
@ -0,0 +1,269 @@
|
|||
2023-05-28 00:08:00 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:11:09 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:14:04 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:21:15 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:22:47 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:36:00 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:36:38 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:39:32 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:41:42 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 00:44:41 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:06:18 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:06:43 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:09:47 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:10:11 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:11:03 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:11:33 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:11:46 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:12:07 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:12:37 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:15:28 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:16:12 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:17:01 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:17:28 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:17:38 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:20:33 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:22:29 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:23:20 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:23:38 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:24:21 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:24:39 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:26:25 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:28:39 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:29:11 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:30:10 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:31:36 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:31:46 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:31:47 [33mwarn[39m [error] Failed to fulfill request to /: secret option required for sessions
|
||||
2023-05-28 01:31:47 [33mwarn[39m [error] Failed to fulfill request to /favicon.ico: secret option required for sessions
|
||||
2023-05-28 01:32:32 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:32:34 [33mwarn[39m [error] Failed to fulfill request to /: secret option required for sessions
|
||||
2023-05-28 01:32:34 [33mwarn[39m [error] Failed to fulfill request to /favicon.ico: secret option required for sessions
|
||||
2023-05-28 01:32:45 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:32:56 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:34:50 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:36:08 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 01:36:25 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:09:21 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:11:16 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:11:58 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:13:02 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:14:03 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:18:24 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 02:18:25 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:19:39 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 02:19:39 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 02:20:44 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 02:20:44 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 16:06:50 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 16:06:50 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 17:45:15 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 17:45:16 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 21:22:50 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:22:51 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 21:25:31 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:25:31 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 21:25:46 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:25:46 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 21:25:56 [33mwarn[39m [error] Failed to fulfill request to /api/session: Username or password incorrect
|
||||
2023-05-28 21:25:56 [31merror[39m [error] HttpError: Username or password incorrect
|
||||
at verifyPassword (/home/niels/Projects/shack/src/users.js:31:9)
|
||||
at async login (/home/niels/Projects/shack/src/users.js:86:2)
|
||||
at async loginApi (/home/niels/Projects/shack/src/web/users.js:7:15)
|
||||
2023-05-28 21:26:02 [33mwarn[39m [error] Failed to fulfill request to /api/session: The client is closed
|
||||
2023-05-28 21:26:02 [31merror[39m [error] Error: The client is closed
|
||||
at Commander._RedisClient_sendCommand (/home/niels/Projects/shack/node_modules/@redis/client/dist/lib/client/index.js:490:31)
|
||||
at Commander.commandsExecutor (/home/niels/Projects/shack/node_modules/@redis/client/dist/lib/client/index.js:188:154)
|
||||
at Commander.BaseClass.<computed> [as set] (/home/niels/Projects/shack/node_modules/@redis/client/dist/lib/commander.js:8:29)
|
||||
at Object.set (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:24:34)
|
||||
at RedisStore.set (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:71:39)
|
||||
at Session.save (/home/niels/Projects/shack/node_modules/express-session/session/session.js:72:25)
|
||||
at Session.save (/home/niels/Projects/shack/node_modules/express-session/index.js:406:15)
|
||||
at ServerResponse.end (/home/niels/Projects/shack/node_modules/express-session/index.js:335:21)
|
||||
at ServerResponse.send (/home/niels/Projects/shack/node_modules/express/lib/response.js:232:10)
|
||||
at ServerResponse.response.send (/home/niels/Projects/shack/node_modules/errors/lib/errors.js:753:22)
|
||||
at ServerResponse.json (/home/niels/Projects/shack/node_modules/express/lib/response.js:278:15)
|
||||
at ServerResponse.send (/home/niels/Projects/shack/node_modules/express/lib/response.js:162:21)
|
||||
at ServerResponse.response.send (/home/niels/Projects/shack/node_modules/errors/lib/errors.js:753:22)
|
||||
at loginApi (/home/niels/Projects/shack/src/web/users.js:14:6)
|
||||
2023-05-28 21:26:02 [33mwarn[39m [error] Failed to fulfill request to /: The client is closed
|
||||
2023-05-28 21:26:02 [31merror[39m [error] Error: The client is closed
|
||||
at Commander._RedisClient_sendCommand (/home/niels/Projects/shack/node_modules/@redis/client/dist/lib/client/index.js:490:31)
|
||||
at Commander.commandsExecutor (/home/niels/Projects/shack/node_modules/@redis/client/dist/lib/client/index.js:188:154)
|
||||
at Commander.BaseClass.<computed> [as get] (/home/niels/Projects/shack/node_modules/@redis/client/dist/lib/commander.js:8:29)
|
||||
at Object.get (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:20:34)
|
||||
at RedisStore.get (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:53:42)
|
||||
at session (/home/niels/Projects/shack/node_modules/express-session/index.js:485:11)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at session (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at Function.handle (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:175:3)
|
||||
at router (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:47:12)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at Immediate.next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at processImmediate (node:internal/timers:468:21)
|
||||
2023-05-28 21:26:30 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:26:30 [32minfo[39m [server] Server running at :::7477
|
||||
2023-05-28 21:26:37 [33mwarn[39m [error] Failed to fulfill request to /api/session: Username or password incorrect
|
||||
2023-05-28 21:26:37 [31merror[39m [error] HttpError: Username or password incorrect
|
||||
at verifyPassword (/home/niels/Projects/shack/src/users.js:31:9)
|
||||
at async login (/home/niels/Projects/shack/src/users.js:86:2)
|
||||
at async loginApi (/home/niels/Projects/shack/src/web/users.js:7:15)
|
||||
2023-05-28 21:51:08 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:51:25 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:51:25 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 21:55:59 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:55:59 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 21:56:12 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 21:56:12 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 22:01:38 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 22:01:39 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 22:05:13 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 22:05:13 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 22:06:29 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 22:06:30 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 22:09:37 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 22:09:37 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 22:10:01 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 22:10:01 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:17:39 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:17:39 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:19:24 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:19:25 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:20:09 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:20:09 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:37:14 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:37:14 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:42:22 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:42:22 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:49:02 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:49:02 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:49:03 [33mwarn[39m [error] Failed to fulfill request to /: [vite-plugin-ssr@0.4.126][Wrong Usage][renderPage(pageContextInit)] You passed 2 arguments but `renderPage()` accepts only one argument.'
|
||||
2023-05-28 23:49:03 [31merror[39m [error] Error: [vite-plugin-ssr@0.4.126][Wrong Usage][renderPage(pageContextInit)] You passed 2 arguments but `renderPage()` accepts only one argument.'
|
||||
at assertArguments (/home/niels/Projects/shack/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/renderPage/assertArguments.js:10:29)
|
||||
at renderPage (/home/niels/Projects/shack/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/renderPage.js:19:43)
|
||||
at defaultHandler (/home/niels/Projects/shack/src/web/default.js:10:29)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at defaultHandler (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at defaultHandler (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/route.js:144:13)
|
||||
at Route.dispatch (/home/niels/Projects/shack/node_modules/express/lib/router/route.js:114:3)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:284:15
|
||||
at param (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:365:14)
|
||||
at param (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:376:14)
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:421:3)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at jsonParser (/home/niels/Projects/shack/node_modules/body-parser/lib/types/json.js:113:7)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at jsonParser (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at setIp (/home/niels/Projects/shack/src/web/ip.js:15:2)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at setIp (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at /home/niels/Projects/shack/node_modules/express-session/index.js:506:7
|
||||
at RedisStore.get (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:56:20)
|
||||
2023-05-28 23:49:03 [33mwarn[39m [error] Failed to fulfill request to /: [vite-plugin-ssr@0.4.126][Wrong Usage][renderPage(pageContextInit)] You passed 2 arguments but `renderPage()` accepts only one argument.'
|
||||
2023-05-28 23:49:03 [31merror[39m [error] Error: [vite-plugin-ssr@0.4.126][Wrong Usage][renderPage(pageContextInit)] You passed 2 arguments but `renderPage()` accepts only one argument.'
|
||||
at assertArguments (/home/niels/Projects/shack/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/renderPage/assertArguments.js:10:29)
|
||||
at renderPage (/home/niels/Projects/shack/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/renderPage.js:19:43)
|
||||
at defaultHandler (/home/niels/Projects/shack/src/web/default.js:10:29)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at defaultHandler (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at defaultHandler (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/route.js:144:13)
|
||||
at Route.dispatch (/home/niels/Projects/shack/node_modules/express/lib/router/route.js:114:3)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:284:15
|
||||
at param (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:365:14)
|
||||
at param (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:376:14)
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:421:3)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at jsonParser (/home/niels/Projects/shack/node_modules/body-parser/lib/types/json.js:113:7)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at jsonParser (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at setIp (/home/niels/Projects/shack/src/web/ip.js:15:2)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at setIp (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at /home/niels/Projects/shack/node_modules/express-session/index.js:506:7
|
||||
at RedisStore.get (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:56:20)
|
||||
2023-05-28 23:49:20 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:49:20 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:49:21 [33mwarn[39m [error] Failed to fulfill request to /: [vite-plugin-ssr@0.4.126][Wrong Usage][renderPage(pageContextInit)] You passed 2 arguments but `renderPage()` accepts only one argument.'
|
||||
2023-05-28 23:49:21 [31merror[39m [error] Error: [vite-plugin-ssr@0.4.126][Wrong Usage][renderPage(pageContextInit)] You passed 2 arguments but `renderPage()` accepts only one argument.'
|
||||
at assertArguments (/home/niels/Projects/shack/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/renderPage/assertArguments.js:10:29)
|
||||
at renderPage (/home/niels/Projects/shack/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/renderPage.js:19:43)
|
||||
at defaultHandler (/home/niels/Projects/shack/src/web/default.js:10:29)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at defaultHandler (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at defaultHandler (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/route.js:144:13)
|
||||
at Route.dispatch (/home/niels/Projects/shack/node_modules/express/lib/router/route.js:114:3)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:284:15
|
||||
at param (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:365:14)
|
||||
at param (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:376:14)
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:421:3)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at jsonParser (/home/niels/Projects/shack/node_modules/body-parser/lib/types/json.js:113:7)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at jsonParser (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at setIp (/home/niels/Projects/shack/src/web/ip.js:15:2)
|
||||
at handleReturn (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
|
||||
at setIp (/home/niels/Projects/shack/node_modules/express-promise-router/lib/express-promise-router.js:64:7)
|
||||
at Layer.handle [as handle_request] (/home/niels/Projects/shack/node_modules/express/lib/router/layer.js:95:5)
|
||||
at trim_prefix (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:328:13)
|
||||
at /home/niels/Projects/shack/node_modules/express/lib/router/index.js:286:9
|
||||
at Function.process_params (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:346:12)
|
||||
at next (/home/niels/Projects/shack/node_modules/express/lib/router/index.js:280:10)
|
||||
at /home/niels/Projects/shack/node_modules/express-session/index.js:506:7
|
||||
at RedisStore.get (/home/niels/Projects/shack/node_modules/connect-redis/dist/cjs/index.js:56:20)
|
||||
2023-05-28 23:50:21 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:50:22 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:54:06 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:54:06 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:55:47 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:55:47 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:56:21 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:56:22 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:57:23 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:57:24 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-28 23:59:13 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-28 23:59:14 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
|
@ -0,0 +1,28 @@
|
|||
2023-05-29 00:03:09 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:03:09 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:03:23 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:03:24 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:06:47 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:06:48 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:11:09 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:11:10 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:11:27 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:11:27 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:13:14 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:13:14 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:14:55 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:14:55 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:15:56 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:15:56 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:23:49 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:23:49 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:24:16 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:24:17 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:32:13 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:32:13 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:34:52 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:34:53 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:35:22 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:35:22 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
||||
2023-05-29 00:42:59 [32minfo[39m [redis] Redis module initialized
|
||||
2023-05-29 00:42:59 [32minfo[39m [server] Server running at 0.0.0.0:7477
|
|
@ -0,0 +1,97 @@
|
|||
exports.up = async function(knex) {
|
||||
await knex.schema.createTable('users', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.text('username', 32)
|
||||
.notNullable()
|
||||
.unique();
|
||||
|
||||
table.text('email', 32)
|
||||
.notNullable()
|
||||
.unique();
|
||||
|
||||
table.text('password')
|
||||
.notNullable();
|
||||
|
||||
table.text('name', 32);
|
||||
table.text('bio', 1000);
|
||||
|
||||
table.specificType('ip', 'inet');
|
||||
|
||||
table.datetime('created_at')
|
||||
.notNullable()
|
||||
.defaultTo(knex.fn.now());
|
||||
});
|
||||
|
||||
await knex.schema.createTable('shelves', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.text('slug')
|
||||
.notNullable();
|
||||
|
||||
table.integer('founder_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('users');
|
||||
|
||||
table.datetime('created_at')
|
||||
.notNullable()
|
||||
.defaultTo(knex.fn.now());
|
||||
});
|
||||
|
||||
await knex.schema.createTable('shelves_settings', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('shelf_id')
|
||||
.primary()
|
||||
.references('id')
|
||||
.inTable('shelves');
|
||||
|
||||
table.text('name');
|
||||
table.text('title');
|
||||
table.text('description');
|
||||
|
||||
table.enum('view_access', ['public', 'registered', 'private'])
|
||||
.notNullable()
|
||||
.defaultTo('public');
|
||||
|
||||
table.enum('post_access', ['registered', 'private'])
|
||||
.notNullable()
|
||||
.defaultTo('public');
|
||||
|
||||
table.boolean('is_nsfw');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('posts', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.text('title')
|
||||
.notNullable();
|
||||
|
||||
table.text('body');
|
||||
table.text('url');
|
||||
|
||||
table.integer('shelf_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('shelves');
|
||||
|
||||
table.integer('user_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('users');
|
||||
|
||||
table.datetime('created_at')
|
||||
.notNullable()
|
||||
.defaultTo(knex.fn.now());
|
||||
});
|
||||
|
||||
await knex.raw(`ALTER TABLE posts ADD CONSTRAINT post_content CHECK (body IS NOT NULL OR url IS NOT NULL)`);
|
||||
};
|
||||
|
||||
exports.down = async function(knex) {
|
||||
await knex.schema.dropTable('posts');
|
||||
await knex.schema.dropTable('shelves_settings');
|
||||
await knex.schema.dropTable('shelves');
|
||||
await knex.schema.dropTable('users');
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "shack",
|
||||
"version": "0.1.0",
|
||||
"description": "Shack is a self-hosted social news aggregate",
|
||||
"main": "src/web/server.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://gitea.unknown.name/DebaucheryLibrarian/shack"
|
||||
},
|
||||
"keywords": [
|
||||
"aggregate",
|
||||
"social",
|
||||
"communities"
|
||||
],
|
||||
"author": "DebaucheryLibrarian",
|
||||
"scripts": {
|
||||
"dev": "npm run server",
|
||||
"prod": "npm run build && npm run server:prod",
|
||||
"build": "vite build",
|
||||
"server": "node ./src/web/server",
|
||||
"server:prod": "cross-env NODE_ENV=production node ./src/web/server",
|
||||
"migrate-make": "knex-migrate generate",
|
||||
"migrate": "knex-migrate up",
|
||||
"rollback": "knex-migrate down"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/cli": "^7.21.5",
|
||||
"@babel/core": "^7.21.8",
|
||||
"@babel/eslint-parser": "^7.21.8",
|
||||
"@babel/preset-env": "^7.21.5",
|
||||
"@hcaptcha/vue3-hcaptcha": "^1.2.1",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vue/compiler-sfc": "^3.2.33",
|
||||
"@vue/server-renderer": "^3.2.33",
|
||||
"bhttp": "^1.2.8",
|
||||
"body-parser": "^1.20.2",
|
||||
"compression": "^1.7.4",
|
||||
"config": "^3.3.9",
|
||||
"connect-redis": "^7.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-vue": "^9.14.0",
|
||||
"express": "^4.18.1",
|
||||
"express-promise-router": "^4.1.1",
|
||||
"express-session": "^1.17.3",
|
||||
"ip-cidr": "^3.1.0",
|
||||
"knex": "^2.4.2",
|
||||
"knex-migrate": "^1.7.4",
|
||||
"nanoid": "^4.0.2",
|
||||
"pg": "^8.11.0",
|
||||
"pinia": "^2.1.3",
|
||||
"redis": "^4.6.6",
|
||||
"sirv": "^2.0.2",
|
||||
"vite": "^4.0.3",
|
||||
"vite-plugin-ssr": "^0.4.126",
|
||||
"vite-plugin-vue-markdown": "^0.23.5",
|
||||
"vite-svg-loader": "^4.0.0",
|
||||
"vue": "^3.2.33",
|
||||
"winston": "^3.9.0",
|
||||
"winston-daily-rotate-file": "^4.7.1",
|
||||
"yargs": "^17.7.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
<template>
|
||||
<div class="content">
|
||||
<h2 class="heading">Create new account</h2>
|
||||
|
||||
<form
|
||||
class="form create"
|
||||
@submit.prevent="signup"
|
||||
>
|
||||
<div
|
||||
v-if="errorMsg"
|
||||
class="form-section form-error"
|
||||
>{{ errorMsg }}</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="form-row">
|
||||
<input
|
||||
v-model="username"
|
||||
placeholder="Username"
|
||||
maxlength="32"
|
||||
class="input"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
placeholder="E-mail"
|
||||
maxlength="500"
|
||||
class="input"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
minlength="8"
|
||||
maxlength="500"
|
||||
placeholder="Password"
|
||||
class="input"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="config.captchaEnabled"
|
||||
class="form-row captcha"
|
||||
>
|
||||
<VueHcaptcha
|
||||
:sitekey="config.captchaKey"
|
||||
@verify="(token) => captchaToken = token"
|
||||
@expired="() => captchaToken = null"
|
||||
@error="() => captchaToken = null"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label class="check-container noselect">
|
||||
<span>
|
||||
<span class="description">I have read and accept the <a
|
||||
href="/help/user-agreement"
|
||||
target="_blank"
|
||||
class="link"
|
||||
>User Agreement</a></span>
|
||||
</span>
|
||||
|
||||
<Checkbox
|
||||
:checked="agreeTos"
|
||||
@change="(checked) => agreeTos = checked"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-row form-actions">
|
||||
<button
|
||||
:disabled="!username || !email || !password || !agreeTos || (config.captchaEnabled && !captchaToken)"
|
||||
class="button button-submit"
|
||||
>Sign up</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
|
||||
|
||||
import Checkbox from '../../components/form/checkbox.vue';
|
||||
|
||||
import navigate from '../../assets/js/navigate';
|
||||
import { post } from '../../assets/js/api';
|
||||
|
||||
const config = CONFIG;
|
||||
|
||||
const username = ref('');
|
||||
const email = ref('');
|
||||
const password = ref('');
|
||||
|
||||
const agreeTos = ref(false);
|
||||
const captchaToken = ref(null);
|
||||
|
||||
const errorMsg = ref(null);
|
||||
|
||||
async function signup() {
|
||||
try {
|
||||
await post('/api/users', {
|
||||
username: username.value,
|
||||
email: email.value,
|
||||
password: password.value,
|
||||
captchaToken: captchaToken.value,
|
||||
});
|
||||
|
||||
navigate('/account/login');
|
||||
} catch (error) {
|
||||
errorMsg.value = error.message;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.create {
|
||||
background: var(--background);
|
||||
padding: 1rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.name {
|
||||
position: relative;
|
||||
|
||||
.input {
|
||||
padding-left: 1.65rem;
|
||||
}
|
||||
|
||||
.prefix {
|
||||
color: var(--shadow);
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: .25rem;
|
||||
letter-spacing: .1rem;
|
||||
padding: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.access {
|
||||
font-weight: bold;
|
||||
margin-bottom: .75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.access-description {
|
||||
margin: .25rem 0 0 1.25rem;
|
||||
color: var(--shadow);
|
||||
font-size: .9rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.nsfw {
|
||||
margin-right: .5rem;
|
||||
font-weight: bold;
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.captcha {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,142 @@
|
|||
<template>
|
||||
<div class="content">
|
||||
<h2 class="heading">Log in</h2>
|
||||
|
||||
<form
|
||||
class="form create"
|
||||
@submit.prevent="signup"
|
||||
>
|
||||
<div
|
||||
v-if="errorMsg"
|
||||
class="form-section form-error"
|
||||
>{{ errorMsg }}</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="form-row">
|
||||
<input
|
||||
v-model="username"
|
||||
placeholder="Username or e-mail"
|
||||
maxlength="500"
|
||||
class="input"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
minlength="8"
|
||||
maxlength="500"
|
||||
placeholder="Password"
|
||||
class="input"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div
|
||||
v-if="$config.public.captchaEnabled"
|
||||
class="form-row captcha"
|
||||
>
|
||||
<VueHcaptcha
|
||||
:sitekey="$config.public.captchaKey"
|
||||
@verify="(token) => captchaToken = token"
|
||||
@expired="() => captchaToken = null"
|
||||
@error="() => captchaToken = null"
|
||||
/>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="form-row form-actions">
|
||||
<button
|
||||
:disabled="!username || !password"
|
||||
class="button button-submit"
|
||||
>Log in</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
// import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
|
||||
|
||||
import { post } from '../../assets/js/api';
|
||||
import navigate from '../../assets/js/navigate';
|
||||
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
|
||||
const errorMsg = ref(null);
|
||||
|
||||
async function signup() {
|
||||
try {
|
||||
await post('/api/session', {
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
});
|
||||
|
||||
navigate('/');
|
||||