init
This commit is contained in:
commit
da75595706
14 changed files with 2033 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
*.log
|
||||||
|
.cache
|
||||||
|
.DS_Store
|
||||||
|
src/.temp
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.vitepress/cache
|
||||||
|
.vitepress/dist
|
56
.vitepress/config.mts
Normal file
56
.vitepress/config.mts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { defineConfig } from 'vitepress'
|
||||||
|
import { defineConfigWithTheme } from 'vitepress'
|
||||||
|
import type { ThemeConfig } from './theme/Config'
|
||||||
|
|
||||||
|
export default defineConfigWithTheme<ThemeConfig>({
|
||||||
|
title: "k0r.386",
|
||||||
|
description: "Norman Köhrings Homepage",
|
||||||
|
themeConfig: {
|
||||||
|
commands: [{
|
||||||
|
command: 'about',
|
||||||
|
aliases: ['info'],
|
||||||
|
help: 'Who is Norman Köhring?',
|
||||||
|
message: 'Norman Köhring is a programmer, hacker and open source enthusiast based in Berlin. He is the Principal Frontend Engineer at Code Gaia, where he is a proud part of revolutionizing carbon emission reporting.',
|
||||||
|
uris: [{
|
||||||
|
label: 'Berlin', uri: 'https://www.openstreetmap.org/#map=12/52.4595/13.5335'
|
||||||
|
}, {
|
||||||
|
label: 'CodeGaia', uri: 'https://codegaia.io/'
|
||||||
|
}, {
|
||||||
|
label: 'Hacker?', uri: 'https://en.wikipedia.org/wiki/Hacker'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
command: 'contact',
|
||||||
|
aliases: ['email'],
|
||||||
|
help: 'How to contact Norman Köhring?',
|
||||||
|
message: [
|
||||||
|
'# other servers',
|
||||||
|
'email - n@koehr.in OR norman.koehring@mailbox.org',
|
||||||
|
'mastodon - mstdn.io/@koehr',
|
||||||
|
'twitter - twitter.com/koehr_in',
|
||||||
|
'github - github.com/nkoehring',
|
||||||
|
'instagram - instagram.com/coffee_n_code',
|
||||||
|
'500px - 500px.com/koehr',
|
||||||
|
'# my server',
|
||||||
|
'sourcecode - git.k0r.in/ (forgejo)',
|
||||||
|
'fediverse - m.k0r.in/@n (misskey)',
|
||||||
|
].join('\n'),
|
||||||
|
uris: [{
|
||||||
|
label: 'email', uri: 'mailto:n@koehr.in'
|
||||||
|
}, {
|
||||||
|
label: 'mastodon', uri: 'https://mstdn.io/@koehr'
|
||||||
|
}, {
|
||||||
|
label: 'twitter', uri: 'https://twitter.com/koehr_in'
|
||||||
|
}, {
|
||||||
|
label: 'github', uri: 'https://github.com/nkoehring'
|
||||||
|
}, {
|
||||||
|
label: 'instagram', uri: 'https://instagram.com/coffee_n_code'
|
||||||
|
}, {
|
||||||
|
label: '500px', uri: 'https://500px.com/koehr'
|
||||||
|
}, {
|
||||||
|
label: 'sourcecode', uri: 'https://git.k0r.in/'
|
||||||
|
}, {
|
||||||
|
label: 'fediverse', uri: 'https://m.k0r.in/@n'
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
})
|
16
.vitepress/theme/Config.ts
Normal file
16
.vitepress/theme/Config.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
export type Uri = {
|
||||||
|
label: string
|
||||||
|
uri: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SimpleCommand = {
|
||||||
|
command: string,
|
||||||
|
aliases?: string[],
|
||||||
|
help?: string,
|
||||||
|
message: string,
|
||||||
|
uris: Uri[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ThemeConfig {
|
||||||
|
commands: SimpleCommand[]
|
||||||
|
}
|
67
.vitepress/theme/Layout.vue
Normal file
67
.vitepress/theme/Layout.vue
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
|
import { useData } from 'vitepress'
|
||||||
|
import useTerminal from './useTerminal'
|
||||||
|
import titleArt from './titles'
|
||||||
|
|
||||||
|
// https://vitepress.dev/reference/runtime-api#usedata
|
||||||
|
const { site, frontmatter } = useData()
|
||||||
|
const enhancedReadability = ref(false)
|
||||||
|
|
||||||
|
const title = computed(() => {
|
||||||
|
const titleKey = frontmatter.value.title
|
||||||
|
const title = titleArt[titleKey] || titleArt['welcome']
|
||||||
|
|
||||||
|
return title.join('\n')
|
||||||
|
})
|
||||||
|
const content = computed(() => frontmatter.value.content ?? [])
|
||||||
|
const commands = computed(() => site.value.themeConfig.commands)
|
||||||
|
|
||||||
|
const prompt = '\n$> '
|
||||||
|
const lines = ref(title.value + '\n\n' + content.value.join('\n') + '\n' + prompt)
|
||||||
|
|
||||||
|
const textArea = ref<HTMLTextAreaElement | null>(null)
|
||||||
|
const footer = ref([])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (textArea.value === null) {
|
||||||
|
console.error('textarea is missing')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { addText, clear, footerLinks } = useTerminal(textArea.value, commands.value)
|
||||||
|
clear()
|
||||||
|
addText('Hello World!')
|
||||||
|
|
||||||
|
watch(footerLinks, () => {
|
||||||
|
footer.value = footerLinks.value
|
||||||
|
}, { immediate: true })
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="screen" :class="{ 'enhanced-readability': enhancedReadability }">
|
||||||
|
<div id="wrap">
|
||||||
|
<div id="interlace" />
|
||||||
|
<div id="scanline" />
|
||||||
|
<div id="inner">
|
||||||
|
<textarea ref="textArea"
|
||||||
|
spellcheck="false"
|
||||||
|
autocorrect="false"
|
||||||
|
autocapitalize="false"
|
||||||
|
autocomplete="false"
|
||||||
|
autofocus
|
||||||
|
></textarea>
|
||||||
|
<footer>
|
||||||
|
<a v-for="({ uri, label}) in footer"
|
||||||
|
:href="uri"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
15
.vitepress/theme/index.ts
Normal file
15
.vitepress/theme/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// https://vitepress.dev/guide/custom-theme
|
||||||
|
import Layout from './Layout.vue'
|
||||||
|
import type { Theme } from 'vitepress'
|
||||||
|
|
||||||
|
import '@fontsource/vt323'
|
||||||
|
import './reset.css'
|
||||||
|
import './style.css'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Layout,
|
||||||
|
enhanceApp({ app, router, siteData }) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
} satisfies Theme
|
||||||
|
|
114
.vitepress/theme/reset.css
Normal file
114
.vitepress/theme/reset.css
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/***
|
||||||
|
The new CSS reset - version 1.11.2 (last updated 15.11.2023)
|
||||||
|
GitHub page: https://github.com/elad2412/the-new-css-reset
|
||||||
|
***/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property
|
||||||
|
- The "symbol *" part is to solve Firefox SVG sprite bug
|
||||||
|
- The "html" element is excluded, otherwise a bug in Chrome breaks the CSS hyphens property (https://github.com/elad2412/the-new-css-reset/issues/36)
|
||||||
|
*/
|
||||||
|
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
|
||||||
|
all: unset;
|
||||||
|
display: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preferred box-sizing value */
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix mobile Safari increase font-size on landscape mode */
|
||||||
|
html {
|
||||||
|
-moz-text-size-adjust: none;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
text-size-adjust: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reapply the pointer cursor for anchor tags */
|
||||||
|
a,
|
||||||
|
button {
|
||||||
|
cursor: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove list styles (bullets/numbers) */
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
menu,
|
||||||
|
summary {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For images to not be able to exceed their container */
|
||||||
|
img {
|
||||||
|
max-inline-size: 100%;
|
||||||
|
max-block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* removes spacing between cells in tables */
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safari - solving issue when using user-select:none on the <body> text input doesn't working */
|
||||||
|
input,
|
||||||
|
textarea {
|
||||||
|
-webkit-user-select: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* revert the 'white-space' property for textarea elements on Safari */
|
||||||
|
textarea {
|
||||||
|
white-space: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* minimum style to allow to style meter element */
|
||||||
|
meter {
|
||||||
|
-webkit-appearance: revert;
|
||||||
|
appearance: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* preformatted text - use only for this feature */
|
||||||
|
:where(pre) {
|
||||||
|
all: revert;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset default text opacity of input placeholder */
|
||||||
|
::placeholder {
|
||||||
|
color: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fix the feature of 'hidden' attribute.
|
||||||
|
display:revert; revert to element instead of attribute */
|
||||||
|
:where([hidden]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* revert for bug in Chromium browsers
|
||||||
|
- fix for the content editable attribute will work properly.
|
||||||
|
- webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element*/
|
||||||
|
:where([contenteditable]:not([contenteditable="false"])) {
|
||||||
|
-moz-user-modify: read-write;
|
||||||
|
-webkit-user-modify: read-write;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
-webkit-line-break: after-white-space;
|
||||||
|
-webkit-user-select: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* apply back the draggable feature - exist only in Chromium and Safari */
|
||||||
|
:where([draggable="true"]) {
|
||||||
|
-webkit-user-drag: element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Revert Modal native behavior */
|
||||||
|
:where(dialog:modal) {
|
||||||
|
all: revert;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove details summary webkit styles */
|
||||||
|
::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
162
.vitepress/theme/style.css
Normal file
162
.vitepress/theme/style.css
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
:root {
|
||||||
|
--black: #000;
|
||||||
|
--white: #FFF;
|
||||||
|
--red: #800;
|
||||||
|
--cyan: #AFE;
|
||||||
|
--violet: #C4C;
|
||||||
|
--green: #0C5;
|
||||||
|
--blue: #00A;
|
||||||
|
--yellow: #EE7;
|
||||||
|
--orange: #D85;
|
||||||
|
--brown: #640;
|
||||||
|
--light-red: #F77;
|
||||||
|
--light-green: #AF6;
|
||||||
|
--light-blue: #08F;
|
||||||
|
--grey-1: #333;
|
||||||
|
--grey-2: #777;
|
||||||
|
--grey-3: #BBB;
|
||||||
|
--crt-frame: #BFBCAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scanline {
|
||||||
|
0% {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
30% {
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--cyan);
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1280px) {
|
||||||
|
#app {
|
||||||
|
width: 90vw;
|
||||||
|
height: 90vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-family: VT323, monospace;
|
||||||
|
font-size: 24px;
|
||||||
|
background: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
background: var(--crt-frame);
|
||||||
|
width: 1280px;
|
||||||
|
height: 900px;
|
||||||
|
max-width: 1280px;
|
||||||
|
max-height: 1024px;
|
||||||
|
box-shadow: inset 0.25em 0.25em 2px rgba(255, 255, 255, 0.4), inset -0.25em -0.25em 2px rgba(0, 0, 0, 0.4);
|
||||||
|
user-select: none;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
perspective: 1000;
|
||||||
|
color: var(--cyan);
|
||||||
|
text-shadow: 0 0 2px yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screen.enhanced-readability {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screen {
|
||||||
|
width: calc(100% - 2.4em);
|
||||||
|
height: calc(100% - 2.4em);
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 1.2em;
|
||||||
|
z-index: 20;
|
||||||
|
box-shadow: 0 0 1px 3px #0A0A0AB2;
|
||||||
|
background: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#app,
|
||||||
|
#screen {
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrap {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
padding: 1.5em;
|
||||||
|
background: radial-gradient(ellipse at center, #FFF2 0%, #0003 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#interlace {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: linear-gradient(#888 50%, #000 0);
|
||||||
|
background-repeat: repeat-y;
|
||||||
|
background-size: 100% 4px;
|
||||||
|
opacity: .1;
|
||||||
|
z-index: 21;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scanline {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1em;
|
||||||
|
background: linear-gradient(180deg, transparent 0, #EEE 50%, navy 0, transparent);
|
||||||
|
opacity: .1;
|
||||||
|
animation: scanline 6s linear infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner {
|
||||||
|
height: 100%;
|
||||||
|
background: #0003;
|
||||||
|
border-radius: .5em;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner::selection {
|
||||||
|
color: var(--blue);
|
||||||
|
background: var(--cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner>textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 1.5em);
|
||||||
|
padding: 0 1em;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner>footer {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
height: 1.5em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner>footer>a {
|
||||||
|
padding: 0 1em;
|
||||||
|
margin-right: 1em;
|
||||||
|
background: var(--cyan);
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
22
.vitepress/theme/titles.ts
Normal file
22
.vitepress/theme/titles.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
export default {
|
||||||
|
welcome: [
|
||||||
|
" ________ __ ",
|
||||||
|
"| | | |.-----.| |.----.-----.--------.-----.",
|
||||||
|
"| | | || -__|| || __| _ | | -__|",
|
||||||
|
"|________||_____||__||____|_____|__|__|__|_____|",
|
||||||
|
],
|
||||||
|
|
||||||
|
aboutMe: [
|
||||||
|
" _______ __ __ _______ ",
|
||||||
|
"| _ | |--.-----.--.--.| |_ | | |.-----.",
|
||||||
|
"| | _ | _ | | || _| | || -__|",
|
||||||
|
"|___|___|_____|_____|_____||____| |__|_|__||_____|",
|
||||||
|
],
|
||||||
|
|
||||||
|
resume: [
|
||||||
|
" ______ ",
|
||||||
|
"| __ \.-----.-----.--.--.--------.-----.",
|
||||||
|
"| <| -__|__ --| | | | -__|",
|
||||||
|
"|___|__||_____|_____|_____|__|__|__|_____|",
|
||||||
|
],
|
||||||
|
}
|
142
.vitepress/theme/useTerminal.ts
Normal file
142
.vitepress/theme/useTerminal.ts
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import type { SimpleCommand, Uri } from './Config'
|
||||||
|
|
||||||
|
export default function useTerminal(inputEl: HTMLTextAreaElement, commands: SimpleCommand[]) {
|
||||||
|
const prompt = '\n$> '
|
||||||
|
const footerLinks = ref([])
|
||||||
|
|
||||||
|
function moveCursorToEnd() {
|
||||||
|
const pos = inputEl.value.length
|
||||||
|
|
||||||
|
// allow text selection
|
||||||
|
if (inputEl.selectionStart !== inputEl.selectionEnd) {
|
||||||
|
console.debug('allowing text selection', inputEl.selectionStart, inputEl.selectionEnd)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
inputEl.setSelectionRange(pos, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFocus() {
|
||||||
|
inputEl.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addText(text: string) {
|
||||||
|
const line = text + prompt
|
||||||
|
inputEl.value = inputEl.value + line
|
||||||
|
inputEl.scrollTop = inputEl.scrollTopMax
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLine(line: string) {
|
||||||
|
addText('\n'+line)
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
inputEl.value = ''
|
||||||
|
addText('')
|
||||||
|
}
|
||||||
|
|
||||||
|
type SYS_OUT = 'NOT_FOUND' | 'USAGE' | 'INFO'
|
||||||
|
|
||||||
|
const SHELL = 'k0rSH'
|
||||||
|
const INFO = 'k0rSH v0.1: the k0r SHell, fiddled together by k0r -- https://k0r.in'
|
||||||
|
const PAD = 16
|
||||||
|
const USAGE = [
|
||||||
|
...commands.map(cmd => {
|
||||||
|
const command = `${(cmd.command+':').padEnd(PAD)}`
|
||||||
|
const help = `${cmd.help ?? 'no helptext provided'}`
|
||||||
|
const aliases = cmd.aliases ? ` (aliases: ${cmd.aliases?.join(', ')})` : ''
|
||||||
|
return `${command}${help}${aliases}`
|
||||||
|
}),
|
||||||
|
`${'help:'.padEnd(PAD)}This help text. (aliases: usage)`,
|
||||||
|
`${'version:'.padEnd(PAD)}Print version information.`,
|
||||||
|
`${'clear:'.padEnd(PAD)}Clear the screen.`,
|
||||||
|
].join('\n')
|
||||||
|
|
||||||
|
function systemOutput(output: SYS_OUT, arg = '') {
|
||||||
|
switch (output) {
|
||||||
|
case 'NOT_FOUND':
|
||||||
|
console.debug('command not found')
|
||||||
|
addLine(`${SHELL}: ${arg}: command not found...`)
|
||||||
|
break
|
||||||
|
case 'USAGE':
|
||||||
|
console.log('help is underway')
|
||||||
|
addLine(`${SHELL} - available commands:\n\n${USAGE}`)
|
||||||
|
break
|
||||||
|
case 'INFO':
|
||||||
|
console.log('explaining myself')
|
||||||
|
addLine(`${SHELL}: ${INFO}`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cursorAtPrompt() {
|
||||||
|
return inputEl.value.endsWith(prompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFooter(uris: Uri[]) {
|
||||||
|
footerLinks.value = uris
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentCommand() {
|
||||||
|
const value = inputEl.value
|
||||||
|
const start = value.lastIndexOf(prompt) + prompt.length
|
||||||
|
const end = value.length
|
||||||
|
|
||||||
|
return value.slice(start, end).trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function execUserCommand(cmd: string) {
|
||||||
|
const userCommand = commands.find(c => {
|
||||||
|
const commandMatch = c.command === cmd
|
||||||
|
const aliasesMatch = c.aliases.includes(cmd)
|
||||||
|
return commandMatch || aliasesMatch
|
||||||
|
})
|
||||||
|
if (!userCommand) return systemOutput('NOT_FOUND', cmd)
|
||||||
|
|
||||||
|
addLine(userCommand.message)
|
||||||
|
setFooter(userCommand.uris)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCurrentCommand() {
|
||||||
|
const cmd = getCurrentCommand()
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
|
addText('')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case 'help':
|
||||||
|
case 'usage':
|
||||||
|
systemOutput('USAGE')
|
||||||
|
break
|
||||||
|
case 'version':
|
||||||
|
systemOutput('INFO')
|
||||||
|
break
|
||||||
|
case 'clear':
|
||||||
|
clear()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
execUserCommand(cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInput(ev) {
|
||||||
|
switch (ev.key) {
|
||||||
|
case 'Enter':
|
||||||
|
handleCurrentCommand()
|
||||||
|
ev.preventDefault()
|
||||||
|
break
|
||||||
|
case 'Backspace':
|
||||||
|
if (cursorAtPrompt()) ev.preventDefault()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputEl.addEventListener('focus', () => moveCursorToEnd())
|
||||||
|
inputEl.addEventListener('blur', () => inputEl.focus())
|
||||||
|
inputEl.addEventListener('click', () => moveCursorToEnd())
|
||||||
|
inputEl.addEventListener('keydown', handleInput)
|
||||||
|
|
||||||
|
return { addText, addLine, setFocus, clear, footerLinks }
|
||||||
|
}
|
49
api-examples.md
Normal file
49
api-examples.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# Runtime API Examples
|
||||||
|
|
||||||
|
This page demonstrates usage of some of the runtime APIs provided by VitePress.
|
||||||
|
|
||||||
|
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
|
||||||
|
|
||||||
|
```md
|
||||||
|
<script setup>
|
||||||
|
import { useData } from 'vitepress'
|
||||||
|
|
||||||
|
const { theme, page, frontmatter } = useData()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
### Theme Data
|
||||||
|
<pre>{{ theme }}</pre>
|
||||||
|
|
||||||
|
### Page Data
|
||||||
|
<pre>{{ page }}</pre>
|
||||||
|
|
||||||
|
### Page Frontmatter
|
||||||
|
<pre>{{ frontmatter }}</pre>
|
||||||
|
```
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useData } from 'vitepress'
|
||||||
|
|
||||||
|
const { site, theme, page, frontmatter } = useData()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
### Theme Data
|
||||||
|
<pre>{{ theme }}</pre>
|
||||||
|
|
||||||
|
### Page Data
|
||||||
|
<pre>{{ page }}</pre>
|
||||||
|
|
||||||
|
### Page Frontmatter
|
||||||
|
<pre>{{ frontmatter }}</pre>
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).
|
13
index.md
Normal file
13
index.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
home: true
|
||||||
|
title: 'welcome'
|
||||||
|
content: [
|
||||||
|
'This is the homepage of Norman Köhring,',
|
||||||
|
'a programmer, OpenSource enthusiast and hacker based in Berlin, Germany.',
|
||||||
|
'',
|
||||||
|
'I call myself a code artist because programming can and should be seen as a creative process. Therefore code is art. I love to craft pieces of art with code that are beautiful and elegant in their simplicity, readability and architecture.',
|
||||||
|
'',
|
||||||
|
'Type "help" to see a list of available commands.',
|
||||||
|
'It is also possible to use the links in the footer.'
|
||||||
|
]
|
||||||
|
---
|
85
markdown-examples.md
Normal file
85
markdown-examples.md
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
# Markdown Extension Examples
|
||||||
|
|
||||||
|
This page demonstrates some of the built-in markdown extensions provided by VitePress.
|
||||||
|
|
||||||
|
## Syntax Highlighting
|
||||||
|
|
||||||
|
VitePress provides Syntax Highlighting powered by [Shikiji](https://github.com/antfu/shikiji), with additional features like line-highlighting:
|
||||||
|
|
||||||
|
**Input**
|
||||||
|
|
||||||
|
````md
|
||||||
|
```js{4}
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
msg: 'Highlighted!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
```js{4}
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
msg: 'Highlighted!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Containers
|
||||||
|
|
||||||
|
**Input**
|
||||||
|
|
||||||
|
```md
|
||||||
|
::: info
|
||||||
|
This is an info box.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
This is a tip.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
This is a warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: danger
|
||||||
|
This is a dangerous warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: details
|
||||||
|
This is a details block.
|
||||||
|
:::
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
::: info
|
||||||
|
This is an info box.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
This is a tip.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
This is a warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: danger
|
||||||
|
This is a dangerous warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: details
|
||||||
|
This is a details block.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).
|
14
package.json
Normal file
14
package.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"docs:dev": "vitepress dev",
|
||||||
|
"docs:build": "vitepress build",
|
||||||
|
"docs:preview": "vitepress preview"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitepress": "1.0.0-rc.31",
|
||||||
|
"vue": "^3.3.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fontsource/vt323": "^5.0.8"
|
||||||
|
}
|
||||||
|
}
|
1268
pnpm-lock.yaml
Normal file
1268
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue