* wip

* wip

* wip
This commit is contained in:
syuilo 2021-03-03 01:03:29 +09:00 committed by GitHub
parent 7e93319873
commit 5e9cc09fcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 271 additions and 5 deletions

View File

@ -45,7 +45,7 @@ gulp.task('build:copy:locales', cb => {
}); });
gulp.task('build:client:script', () => { gulp.task('build:client:script', () => {
return gulp.src(['./src/server/web/boot.js']) return gulp.src(['./src/server/web/boot.js', './src/server/web/bios.js', './src/server/web/cli.js'])
.pipe(replace('VERSION', JSON.stringify(meta.version))) .pipe(replace('VERSION', JSON.stringify(meta.version)))
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales)))) .pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
.pipe(terser({ .pipe(terser({
@ -55,7 +55,7 @@ gulp.task('build:client:script', () => {
}); });
gulp.task('build:client:style', () => { gulp.task('build:client:style', () => {
return gulp.src(['./src/server/web/style.css']) return gulp.src(['./src/server/web/style.css', './src/server/web/bios.css', './src/server/web/cli.css'])
.pipe(cssnano()) .pipe(cssnano())
.pipe(gulp.dest('./built/server/web/')); .pipe(gulp.dest('./built/server/web/'));
}); });

View File

@ -8,7 +8,7 @@
<Fa :icon="faExternalLinkAlt" class="icon"/> <Fa :icon="faExternalLinkAlt" class="icon"/>
</span> </span>
</a> </a>
<MkA class="main _button _formPanel _formClickable" :class="{ active }" :to="to" v-else> <MkA class="main _button _formPanel _formClickable" :class="{ active }" :to="to" :behavior="behavior" v-else>
<span class="icon"><slot name="icon"></slot></span> <span class="icon"><slot name="icon"></slot></span>
<span class="text"><slot></slot></span> <span class="text"><slot></slot></span>
<span class="right"> <span class="right">
@ -38,6 +38,10 @@ export default defineComponent({
type: Boolean, type: Boolean,
required: false required: false
}, },
behavior: {
type: String,
required: false,
},
}, },
data() { data() {
return { return {

View File

@ -98,6 +98,11 @@ export default defineComponent({
}, },
nav() { nav() {
if (this.behavior === 'browser') {
location.href = this.to;
return;
}
if (this.to.startsWith('/my/messaging')) { if (this.to.startsWith('/my/messaging')) {
if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window(); if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window();
if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout(); if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout();

View File

@ -23,13 +23,16 @@
<FormLink to="/settings/registry"><template #icon><Fa :icon="faCogs"/></template>{{ $ts.registry }}</FormLink> <FormLink to="/settings/registry"><template #icon><Fa :icon="faCogs"/></template>{{ $ts.registry }}</FormLink>
<FormLink to="/bios" behavior="browser"><template #icon><Fa :icon="faDoorOpen"/></template>BIOS</FormLink>
<FormLink to="/cli" behavior="browser"><template #icon><Fa :icon="faDoorOpen"/></template>CLI</FormLink>
<FormButton @click="closeAccount" danger>{{ $ts.closeAccount }}</FormButton> <FormButton @click="closeAccount" danger>{{ $ts.closeAccount }}</FormButton>
</FormBase> </FormBase>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue'; import { defineAsyncComponent, defineComponent } from 'vue';
import { faEllipsisH, faCogs } from '@fortawesome/free-solid-svg-icons'; import { faEllipsisH, faCogs, faDoorOpen } from '@fortawesome/free-solid-svg-icons';
import FormSwitch from '@/components/form/switch.vue'; import FormSwitch from '@/components/form/switch.vue';
import FormSelect from '@/components/form/select.vue'; import FormSelect from '@/components/form/select.vue';
import FormLink from '@/components/form/link.vue'; import FormLink from '@/components/form/link.vue';
@ -61,7 +64,7 @@ export default defineComponent({
icon: faEllipsisH icon: faEllipsisH
}, },
debug, debug,
faCogs faCogs, faDoorOpen,
} }
}, },

40
src/server/web/bios.css Normal file
View File

@ -0,0 +1,40 @@
* {
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
}
html {
background: #ffb4e1;
}
main {
background: #dedede;
}
main > .tabs {
padding: 16px;
border-bottom: solid 4px #c3c3c3;
}
#lsEditor > .adder {
margin: 16px;
padding: 16px;
border: solid 2px #c3c3c3;
}
#lsEditor > .adder > textarea {
display: block;
width: 100%;
min-height: 5em;
box-sizing: border-box;
}
#lsEditor > .record {
padding: 16px;
border-bottom: solid 1px #c3c3c3;
}
#lsEditor > .record > header {
font-weight: bold;
}
#lsEditor > .record > textarea {
display: block;
width: 100%;
min-height: 5em;
box-sizing: border-box;
}

87
src/server/web/bios.js Normal file
View File

@ -0,0 +1,87 @@
'use strict';
window.onload = async () => {
const account = JSON.parse(localStorage.getItem('account'));
const i = account.token;
const api = (endpoint, data = {}) => {
const promise = new Promise((resolve, reject) => {
// Append a credential
if (i) data.i = i;
// Send request
fetch(endpoint.indexOf('://') > -1 ? endpoint : `/api/${endpoint}`, {
method: 'POST',
body: JSON.stringify(data),
credentials: 'omit',
cache: 'no-cache'
}).then(async (res) => {
const body = res.status === 204 ? null : await res.json();
if (res.status === 200) {
resolve(body);
} else if (res.status === 204) {
resolve();
} else {
reject(body.error);
}
}).catch(reject);
});
return promise;
};
const content = document.getElementById('content');
document.getElementById('ls').addEventListener('click', () => {
content.innerHTML = '';
const lsEditor = document.createElement('div');
lsEditor.id = 'lsEditor';
const adder = document.createElement('div');
adder.classList.add('adder');
const addKeyInput = document.createElement('input');
const addValueTextarea = document.createElement('textarea');
const addButton = document.createElement('button');
addButton.textContent = 'add';
addButton.addEventListener('click', () => {
localStorage.setItem(addKeyInput.value, addValueTextarea.value);
location.reload();
});
adder.appendChild(addKeyInput);
adder.appendChild(addValueTextarea);
adder.appendChild(addButton);
lsEditor.appendChild(adder);
for (let i = 0; i < localStorage.length; i++) {
const k = localStorage.key(i);
const record = document.createElement('div');
record.classList.add('record');
const header = document.createElement('header');
header.textContent = k;
const textarea = document.createElement('textarea');
textarea.textContent = localStorage.getItem(k);
const saveButton = document.createElement('button');
saveButton.textContent = 'save';
saveButton.addEventListener('click', () => {
localStorage.setItem(k, textarea.value);
location.reload();
});
const removeButton = document.createElement('button');
removeButton.textContent = 'remove';
removeButton.addEventListener('click', () => {
localStorage.removeItem(k);
location.reload();
});
record.appendChild(header);
record.appendChild(textarea);
record.appendChild(saveButton);
record.appendChild(removeButton);
lsEditor.appendChild(record);
}
content.appendChild(lsEditor);
});
};

19
src/server/web/cli.css Normal file
View File

@ -0,0 +1,19 @@
* {
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
}
html {
background: #ffb4e1;
}
main {
background: #dedede;
}
#tl > div {
padding: 16px;
border-bottom: solid 1px #c3c3c3;
}
#tl > div > header {
font-weight: bold;
}

55
src/server/web/cli.js Normal file
View File

@ -0,0 +1,55 @@
'use strict';
window.onload = async () => {
const account = JSON.parse(localStorage.getItem('account'));
const i = account.token;
const api = (endpoint, data = {}) => {
const promise = new Promise((resolve, reject) => {
// Append a credential
if (i) data.i = i;
// Send request
fetch(endpoint.indexOf('://') > -1 ? endpoint : `/api/${endpoint}`, {
method: 'POST',
body: JSON.stringify(data),
credentials: 'omit',
cache: 'no-cache'
}).then(async (res) => {
const body = res.status === 204 ? null : await res.json();
if (res.status === 200) {
resolve(body);
} else if (res.status === 204) {
resolve();
} else {
reject(body.error);
}
}).catch(reject);
});
return promise;
};
document.getElementById('submit').addEventListener('click', () => {
api('notes/create', {
text: document.getElementById('text').value
}).then(() => {
location.reload();
});
});
api('notes/timeline').then(notes => {
const tl = document.getElementById('tl');
for (const note of notes) {
const el = document.createElement('div');
const name = document.createElement('header');
name.textContent = `${note.user.name} @${note.user.username}`;
const text = document.createElement('div');
text.textContent = `${note.text}`;
el.appendChild(name);
el.appendChild(text);
tl.appendChild(el);
}
});
};

View File

@ -376,6 +376,18 @@ router.get('/info', async ctx => {
}); });
}); });
router.get('/bios', async ctx => {
await ctx.render('bios', {
version: config.version,
});
});
router.get('/cli', async ctx => {
await ctx.render('cli', {
version: config.version,
});
});
const override = (source: string, target: string, depth: number = 0) => const override = (source: string, target: string, depth: number = 0) =>
[, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/'); [, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/');

View File

@ -0,0 +1,20 @@
doctype html
html
head
meta(charset='utf-8')
meta(name='application-name' content='Misskey')
title Misskey BIOS
style
include ../bios.css
script
include ../bios.js
body
header
h1 Misskey BIOS #{version}
main
div.tabs
button#ls edit local storage
div#content

View File

@ -0,0 +1,21 @@
doctype html
html
head
meta(charset='utf-8')
meta(name='application-name' content='Misskey')
title Misskey Cli
style
include ../cli.css
script
include ../cli.js
body
header
h1 Misskey Cli #{version}
main
div#form
textarea#text
button#submit submit
div#tl