parent
							
								
									7e93319873
								
							
						
					
					
						commit
						5e9cc09fcb
					
				
					 11 changed files with 271 additions and 5 deletions
				
			
		|  | @ -45,7 +45,7 @@ gulp.task('build:copy:locales', cb => { | |||
| }); | ||||
| 
 | ||||
| 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('LANGS', JSON.stringify(Object.keys(locales)))) | ||||
| 		.pipe(terser({ | ||||
|  | @ -55,7 +55,7 @@ gulp.task('build:client:script', () => { | |||
| }); | ||||
| 
 | ||||
| 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(gulp.dest('./built/server/web/')); | ||||
| }); | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ | |||
| 			<Fa :icon="faExternalLinkAlt" class="icon"/> | ||||
| 		</span> | ||||
| 	</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="text"><slot></slot></span> | ||||
| 		<span class="right"> | ||||
|  | @ -38,6 +38,10 @@ export default defineComponent({ | |||
| 			type: Boolean, | ||||
| 			required: false | ||||
| 		}, | ||||
| 		behavior: { | ||||
| 			type: String, | ||||
| 			required: false, | ||||
| 		}, | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
|  |  | |||
|  | @ -98,6 +98,11 @@ export default defineComponent({ | |||
| 		}, | ||||
| 
 | ||||
| 		nav() { | ||||
| 			if (this.behavior === 'browser') { | ||||
| 				location.href = this.to; | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			if (this.to.startsWith('/my/messaging')) { | ||||
| 				if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window(); | ||||
| 				if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout(); | ||||
|  |  | |||
|  | @ -23,13 +23,16 @@ | |||
| 
 | ||||
| 	<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> | ||||
| </FormBase> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| 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 FormSelect from '@/components/form/select.vue'; | ||||
| import FormLink from '@/components/form/link.vue'; | ||||
|  | @ -61,7 +64,7 @@ export default defineComponent({ | |||
| 				icon: faEllipsisH | ||||
| 			}, | ||||
| 			debug, | ||||
| 			faCogs | ||||
| 			faCogs, faDoorOpen, | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										40
									
								
								src/server/web/bios.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/server/web/bios.css
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										87
									
								
								src/server/web/bios.js
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										19
									
								
								src/server/web/cli.css
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										55
									
								
								src/server/web/cli.js
									
										
									
									
									
										Normal 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); | ||||
| 		} | ||||
| 	}); | ||||
| }; | ||||
|  | @ -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) => | ||||
| 	[, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/'); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										20
									
								
								src/server/web/views/bios.pug
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/server/web/views/bios.pug
									
										
									
									
									
										Normal 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 | ||||
							
								
								
									
										21
									
								
								src/server/web/views/cli.pug
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/server/web/views/cli.pug
									
										
									
									
									
										Normal 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 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue