2022-06-12 14:22:15 +02:00
import type { Diary , Project } from "../content/types" ;
2021-12-17 18:55:00 +01:00
import type { Command , Flag } from "./types" ;
2022-06-12 14:55:48 +02:00
import Color from "color" ;
2022-08-23 10:10:45 +02:00
import { getColors , setColors } from "../colors" ;
import Rainbow from "../colors" ;
2022-09-30 19:38:25 +02:00
import styles from "../../styles/Terminal/Random.module.scss" ;
2021-12-16 00:21:14 +01:00
2022-06-12 14:55:48 +02:00
function getCommandByName ( name : string ) : Command | undefined {
2021-12-17 19:04:34 +01:00
return commandList . find ( cmd = > cmd . name === name ) ;
}
2021-12-16 00:21:14 +01:00
function illegalUse ( raw : string , cmd : Command ) : string [ ] {
return [
"Syntax error!" ,
` Cannot parse " ${ raw } " ` ,
""
] . concat ( printSyntax ( cmd ) ) ;
}
function checkFlags ( flags : string [ ] , cmd : Command ) : boolean {
2022-09-30 15:40:26 +02:00
if ( ! flags || flags . length === 0 ) return true ;
2021-12-16 00:21:14 +01:00
if ( ! cmd . flags ) return false ;
for ( const flag of flags ) {
2022-06-12 14:55:48 +02:00
const isLong = flag . substring ( 0 , 2 ) === "--" ;
2021-12-17 20:02:42 +01:00
const flagObj = Object . values ( cmd . flags ) . find ( f = > isLong ? f . long === flag . substring ( 2 ) : f . short === flag . substring ( 1 ) ) ;
2021-12-16 00:21:14 +01:00
if ( ! flagObj ) return false ;
}
return true ;
}
function checkSubcmd ( subcmds : string [ ] , cmd : Command ) : boolean {
2022-09-30 15:40:26 +02:00
if ( ! subcmds || subcmds . length === 0 ) return true ;
2021-12-16 00:21:14 +01:00
if ( ! cmd . subcommands ) return false ;
for ( const sc of subcmds ) {
2021-12-17 20:02:42 +01:00
const flagObj = Object . values ( cmd . subcommands ) . find ( s = > s . name === sc ) ;
2021-12-16 00:21:14 +01:00
if ( ! flagObj ) return false ;
}
return true ;
}
2021-12-17 18:55:00 +01:00
function checkFlagInclude ( flagsProvided : string [ ] , flag : Flag ) : boolean {
2021-12-17 20:02:42 +01:00
if ( ! flag ) return false ;
2021-12-17 18:55:00 +01:00
return flagsProvided . includes ( ` - ${ flag . short } ` ) || flagsProvided . includes ( ` -- ${ flag . long } ` ) ;
}
2021-12-16 00:21:14 +01:00
export function printSyntax ( cmd : Command ) : string [ ] {
let flagsOption = "" ;
let flagsDesc = [ ] ;
2021-12-17 20:02:42 +01:00
if ( cmd . flags && Object . keys ( cmd . flags ) . length > 0 ) {
2021-12-16 00:21:14 +01:00
flagsOption = " [" ;
2021-12-16 01:03:54 +01:00
flagsDesc . push ( "" ) ;
2021-12-16 00:21:14 +01:00
flagsDesc . push ( "Flags:" ) ;
2021-12-17 20:02:42 +01:00
Object . values ( cmd . flags ) . forEach ( ( flag = > {
2021-12-16 00:21:14 +01:00
flagsOption += ` - ${ flag . short } ` ;
flagsDesc . push ( ` \ t- ${ flag . short } \ t-- ${ flag . long } \ t ${ flag . desc } ` ) ;
} ) ) ;
2022-06-12 14:55:48 +02:00
flagsOption = flagsOption . substring ( 0 , flagsOption . length - 1 ) + "]" ;
2021-12-16 00:21:14 +01:00
}
let subcmdOption = "" ;
let subcmdDesc = [ ] ;
2021-12-17 20:02:42 +01:00
if ( cmd . subcommands && Object . keys ( cmd . subcommands ) . length > 0 ) {
2021-12-16 00:21:14 +01:00
subcmdOption = " [" ;
2021-12-16 01:03:54 +01:00
subcmdDesc . push ( "" ) ;
2021-12-17 19:04:34 +01:00
subcmdDesc . push ( "Arguments:" ) ;
2021-12-17 20:02:42 +01:00
Object . values ( cmd . subcommands ) . forEach ( ( subcmd = > {
2021-12-16 00:21:14 +01:00
subcmdOption += ` ${ subcmd . name } | ` ;
2021-12-17 20:02:42 +01:00
subcmdDesc . push ( ` \ t ${ subcmd . name } \ t ${ subcmd . desc } ` ) ;
2021-12-16 00:21:14 +01:00
} ) ) ;
2022-06-12 14:55:48 +02:00
subcmdOption = subcmdOption . substring ( 0 , subcmdOption . length - 1 ) + "]" ;
2021-12-16 00:21:14 +01:00
}
2022-06-12 14:55:48 +02:00
return [ ` Usage: ${ cmd . name } ${ flagsOption } ${ subcmdOption } ` ] . concat ( flagsDesc ) . concat ( subcmdDesc ) ;
2021-12-16 00:21:14 +01:00
}
const about : Command = {
name : "about" ,
desc : "Show information about this page." ,
2021-12-17 20:02:42 +01:00
execute : ( ) = > {
2021-12-16 00:21:14 +01:00
return [
"Hello there wanderer." ,
"So you want to know what this is about?" ,
"" ,
"Well, the answer is pretty unspectecular:" ,
2022-08-23 13:09:20 +02:00
"This site presents some stuff that me, a human, created." ,
2022-07-30 15:45:09 +02:00
"If you look arround you can read about my various projects." ,
2021-12-16 00:21:14 +01:00
"" ,
"The navigation is done via this console interface." ,
"Even when you open a project page you don't need your mouse - just press Esc to close it." ,
"" ,
"I hope you enjoy your stay here!" ,
2022-07-30 15:45:09 +02:00
"If you want to know more about the creation of this page, type %{project this}." ,
"" ,
"If you are kind of lost what to do, type %{help --this}."
2021-12-16 00:21:14 +01:00
] ;
}
} ;
2021-12-17 18:55:00 +01:00
const help : Command = {
name : "help" ,
desc : "Shows helptext." ,
2022-06-12 14:55:48 +02:00
flags : { more : { long : "this" , short : "t" , desc : "Show information about this site." } } ,
2021-12-17 20:02:42 +01:00
execute : ( flags ) = > {
if ( help . flags && checkFlagInclude ( flags , help . flags . more ) ) {
2021-12-17 18:55:00 +01:00
return [
"Hello user!" ,
2022-07-30 15:45:09 +02:00
"What you see here should resemble a CLI. If you ever used Linux this should be pretty easy for you." ,
"" ,
"Everyone else: Have no fear. It is pretty simple." ,
"You just type in commands and the output is shown here or it does something on the webite." ,
"To find out, which commands are available, you can type %{help}." ,
"" ,
"When wanting to know how to use a command, type %{man <command>} or %{<command> --help}." ,
2021-12-17 18:55:00 +01:00
"" ,
"Have fun!"
] ;
} else {
const available = [ "Available commands:" ] ;
2022-07-30 15:45:09 +02:00
commandList . filter ( cmd = > ! cmd . hidden ) . forEach ( cmd = > available . push ( ` \ t ${ cmd . name } \ t ${ cmd . desc } ` ) ) ;
available . push ( "" ) ;
a vailable . push ( "Need help about the general usage? Type %{help --this}!" ) ;
2021-12-17 18:55:00 +01:00
return available ;
}
}
} ;
2021-12-17 19:04:34 +01:00
const man : Command = {
name : "man" ,
desc : "Provides a manual for a command." ,
2021-12-17 20:02:42 +01:00
subcommands : {
2022-06-12 14:55:48 +02:00
command : { name : "command" , desc : "Name of a command" }
2021-12-17 20:02:42 +01:00
} ,
execute : ( _flags , args ) = > {
2021-12-17 19:04:34 +01:00
if ( args . length !== 1 ) {
return printSyntax ( man ) ;
} else {
const cmd = getCommandByName ( args [ 0 ] ) ;
if ( ! cmd ) return [ ` Cannot find command ' ${ args [ 0 ] } '. ` ] ;
else return printSyntax ( cmd ) ;
}
}
} ;
2021-12-17 20:02:42 +01:00
const project : Command = {
name : "project" ,
desc : "Show information about a project." ,
flags : {
2022-06-12 14:55:48 +02:00
minimal : { short : "m" , long : "minimal" , desc : "Only show minimal information." } ,
source : { short : "s" , long : "source" , desc : "Open git repository of project." } ,
list : { short : "l" , long : "list" , desc : "\tShow list of projects." }
2021-12-17 20:02:42 +01:00
} ,
2022-07-29 14:22:51 +02:00
subcommands : { name : { name : "name" , desc : "Name of the project." } , page : { name : "page" , desc : "Page of the diary (only for diaries; 0 is mainpage)." } } ,
2022-01-14 14:27:19 +01:00
execute : ( flags , args , _raw , cmdIf ) = > {
2021-12-17 20:02:42 +01:00
if ( project . flags && checkFlagInclude ( flags , project . flags . list ) ) {
const result = [ "Found the following projects:" ] ;
2022-06-12 14:22:15 +02:00
const projects = cmdIf . content . filter ( p = > p . type === "project" ) ;
2022-06-12 14:55:48 +02:00
if ( projects . length === 0 ) result . push ( "\tNo projects found." ) ;
2022-06-12 14:22:15 +02:00
else projects . forEach ( project = > result . push ( ` \ t ${ project . name } \ t ${ project . short_desc } ` ) ) ;
2022-03-15 17:21:10 +01:00
result . push ( "And the following diaries:" ) ;
2022-06-12 14:22:15 +02:00
const diaries = cmdIf . content . filter ( p = > p . type === "diary" ) ;
2022-06-12 14:55:48 +02:00
if ( diaries . length === 0 ) result . push ( "\tNo diaries found." ) ;
2022-06-12 14:22:15 +02:00
else diaries . forEach ( diary = > result . push ( ` \ t ${ diary . name } \ t ${ diary . short_desc } ` ) ) ;
2021-12-17 20:02:42 +01:00
return result ;
}
2022-07-29 14:22:51 +02:00
if ( args . length < 1 || args . length > 2 ) return printSyntax ( project ) ;
2021-12-17 20:02:42 +01:00
if ( args [ 0 ] === "this" ) args [ 0 ] = "homepage" ;
2022-06-12 14:55:48 +02:00
let [ pjt ] = [ cmdIf . content . find ( p = > p . name === args [ 0 ] ) as Project | Diary | undefined ] ;
2021-12-17 20:02:42 +01:00
if ( ! pjt ) return [
` Cannot find project ${ args [ 0 ] } ! ` ,
"You can see available projects using 'project -l'."
] ;
if ( project . flags && checkFlagInclude ( flags , project . flags . source ) ) {
try {
window && window . open ( pjt . repo , "_blank" ) ;
return [ "Opened repository in new tab." ] ;
} catch {
return [ "Sorry, no repository for this project." ] ;
}
}
if ( project . flags && checkFlagInclude ( flags , project . flags . minimal ) ) return pjt . desc ;
2022-07-29 14:22:51 +02:00
const result : string [ ] = [ ] ;
let selectedPage : number | undefined = Number . parseInt ( args [ 1 ] || "" ) ;
if ( args [ 1 ] ) {
if ( Number . isNaN ( selectedPage ) ) {
result . push ( "Invalid page number, ignoring it." ) ;
selectedPage = undefined ;
} else {
if ( pjt . type !== "diary" ) {
result . push ( "This is not a diary, ignoring page." ) ;
selectedPage = undefined ;
} else {
if ( selectedPage < 0 || selectedPage > pjt . entries . length ) {
result . push ( "Invalid page number, ignoring it." ) ;
selectedPage = undefined ;
}
}
}
} else {
selectedPage = undefined ;
}
if ( cmdIf . callbacks ? . setModalContent ) cmdIf . callbacks . setModalContent ( pjt , selectedPage ) ;
2022-06-12 14:22:15 +02:00
if ( cmdIf . callbacks ? . setModalVisible ) cmdIf . callbacks . setModalVisible ( true ) ;
2022-07-29 14:22:51 +02:00
return result ;
2021-12-17 20:02:42 +01:00
}
} ;
2021-12-26 14:07:46 +01:00
const exitCmd : Command = {
name : "exit" ,
2021-12-26 15:37:08 +01:00
desc : "Tries to close this tab." ,
2021-12-26 14:07:46 +01:00
execute : ( ) = > {
if ( typeof window !== undefined ) {
window . opener = null ;
2022-01-05 17:52:20 +01:00
window . open ( "" , "_self" ) ;
2021-12-26 14:07:46 +01:00
window . close ( ) ;
}
return [
"If you can read this, closing the window did not work." ,
2021-12-26 15:37:08 +01:00
"This is most likely because of a restriction in JavaScript." ,
"#{Read more here|https://developer.mozilla.org/en-US/docs/Web/API/Window/close}."
2022-01-05 17:52:20 +01:00
] ;
2021-12-26 14:07:46 +01:00
}
2022-01-05 17:52:20 +01:00
} ;
2021-12-26 14:07:46 +01:00
2021-12-26 14:17:11 +01:00
const clear : Command = {
name : "clear" ,
desc : "Clears the output on screen." ,
execute : ( ) = > [ ]
2022-01-05 17:52:20 +01:00
} ;
2021-12-26 14:17:11 +01:00
2022-06-12 14:55:48 +02:00
const color : Command = {
name : "color" ,
desc : "Changes the color of the site." ,
subcommands : {
reset : { name : "reset" , desc : "Resets the color." } ,
2022-06-20 23:37:34 +02:00
value : { name : "value" , desc : "Any valid (css) color value." } ,
2022-06-12 14:55:48 +02:00
} ,
2022-06-12 20:15:16 +02:00
execute : ( _flags , args , _raw , cmdIf ) = > {
2022-06-12 14:55:48 +02:00
if ( ! window || ! window . document ) return [ ] ;
2022-06-21 18:44:20 +02:00
if ( args . length === 0 ) {
const colors = getColors ( ) ;
return [
"Current colors:" ,
` Text: \ t \ t ${ colors [ 0 ] } ` ,
` Links: \ t \ t ${ colors [ 1 ] } ` ,
` Completion: \ t ${ colors [ 2 ] } `
] ;
}
2022-06-12 14:55:48 +02:00
if ( args [ 0 ] === "reset" ) {
2022-08-23 10:10:45 +02:00
Rainbow . stop ( ) ;
2022-06-12 14:55:48 +02:00
window . document . documentElement . style . removeProperty ( "--repl-color" ) ;
window . document . documentElement . style . removeProperty ( "--repl-color-link" ) ;
window . document . documentElement . style . removeProperty ( "--repl-color-hint" ) ;
return [ "Color reset." ] ;
} else {
2022-06-12 19:57:34 +02:00
let color : Color ;
2022-06-12 14:55:48 +02:00
try {
2022-06-21 18:44:20 +02:00
color = Color ( args . join ( " " ) . trim ( ) ) ;
2022-06-12 14:55:48 +02:00
} catch {
return [ "Invalid color!" ] ;
}
2022-08-23 10:10:45 +02:00
Rainbow . stop ( ) ;
2022-06-21 18:44:20 +02:00
setColors ( color ) ;
2022-06-12 20:15:16 +02:00
switch ( true ) {
case color . hex ( ) . toLowerCase ( ) === "#1f1e33" : {
2022-07-30 15:59:19 +02:00
if ( cmdIf . callbacks ? . setModalHTML && cmdIf . callbacks ? . setModalVisible ) {
2022-07-30 17:48:18 +02:00
cmdIf . callbacks ? . setModalHTML ( `
< div class = "${styles.modalVideoContainer}" >
< iframe width = "100%" height = "100%" src = "https://www.youtube-nocookie.com/embed/w4U9S5eX3eY" title = "YouTube video player" frameborder = "0" allow = "autoplay; clipboard-write; encrypted-media; picture-in-picture" allowfullscreen > < / iframe >
< / div > ` );
2022-07-30 15:59:19 +02:00
cmdIf . callbacks ? . setModalVisible ( true ) ;
}
2022-06-12 20:15:16 +02:00
break ;
}
}
2022-06-12 19:57:34 +02:00
return [ "Color set | #{Link|#} | %{help}" ] ;
2022-06-12 14:55:48 +02:00
}
}
} ;
2022-06-21 18:44:20 +02:00
const save : Command = {
name : "save" ,
desc : "Saves the current color and command history to local storage." ,
subcommands : {
clear : { name : "clear" , desc : "Clear the saved data." } ,
2022-08-22 14:10:07 +02:00
confirm : { name : "confirm" , desc : "You explicitly confirm, you allow saving to the local storage." } ,
2022-06-21 18:44:20 +02:00
} ,
2022-08-22 14:10:07 +02:00
flags : {
color : { short : "c" , long : "color" , desc : "Only save the color." } ,
history : { short : "h" , long : "history" , desc : "Only save the history." } ,
} ,
execute : ( flags , args , _raw , cmdIf ) = > {
2022-06-21 18:44:20 +02:00
const defaultRet = [
"You can save the current color and command history to local storage." ,
"To do so, use %{save confirm}." ,
"By using this command above you agree on saving the non-functional data to local storage." ,
"The data will never leave your computer!"
] ;
if ( args . length === 0 ) {
return defaultRet ;
} else if ( args [ 0 ] === "clear" ) {
window . localStorage . clear ( ) ;
return [ "Colors and history removed from storage." ] ;
} else if ( args [ 0 ] === "confirm" ) {
2022-08-22 14:10:07 +02:00
const saveColor = save . flags && checkFlagInclude ( flags , save . flags . color ) ;
const saveHistory = save . flags && checkFlagInclude ( flags , save . flags . history ) ;
const saveAll = ! saveColor && ! saveHistory ;
2022-06-21 18:44:20 +02:00
const result = [ ] ;
2022-08-22 14:10:07 +02:00
if ( saveColor || saveAll ) {
const currentColors = getColors ( ) ;
const color = new Color ( currentColors [ 0 ] ) ;
if ( color . contrast ( new Color ( "#000" ) ) < 1.1 || color . alpha ( ) < 0.1 ) result . push ( "Skipping saving the color because it's too dark." ) ;
else {
window . localStorage . setItem ( "color" , currentColors [ 0 ] ) ;
result . push ( "Color saved to local storage." ) ;
}
2022-06-22 22:07:46 +02:00
}
2022-06-21 18:44:20 +02:00
2022-08-22 14:10:07 +02:00
if ( saveHistory || saveAll ) {
const history = cmdIf . callbacks ? . getCmdHistory ? cmdIf . callbacks . getCmdHistory ( ) : [ ] ;
window . localStorage . setItem ( "history" , JSON . stringify ( history ) ) ;
result . push ( "History saved to storage." ) ;
}
2022-06-21 18:44:20 +02:00
return result ;
} else {
return printSyntax ( save ) ;
}
} ,
} ;
2022-07-30 15:45:09 +02:00
const pingi : Command = {
name : "pingi" ,
desc : "<3" ,
2022-07-30 15:59:19 +02:00
execute : ( _flags , _args , _raw , cmdIf ) = > {
2022-07-30 17:48:18 +02:00
const pingiImg = [
"hJQFR4dpyyZskjmbAkvlnNYi" ,
"LjwTg8qftDGLDfYyNH5OMY6L" ,
"niaM6yPxKBQV8umkh0xpkbCH" ,
"7hcMiKlbn9QWNbwA3DFcpk6A" ,
"xFnQEWlO5jqvJ4lruK4C8zfq" ,
"CplNRTMYuwmSW8WH2UxCi5NU" ,
"oQ03IzrBkLwCwsUtdp3zn0nW" ,
"36zkZSuWmhAa89ErDR4myYW0" ,
"HZvdYHr4fqYRTkTn8zw4akjA" ,
"VdTAABUXCpo5Gom7aszQDw1c" ,
"zwIJwof4beiqDiy3PBkYmZYd"
] ;
2022-07-30 15:59:19 +02:00
if ( cmdIf . callbacks ? . setModalHTML && cmdIf . callbacks . setModalVisible ) {
2022-07-30 17:48:18 +02:00
const img = pingiImg [ Math . floor ( Math . random ( ) * pingiImg . length ) ] ;
cmdIf . callbacks . setModalHTML ( `
< a href = "https://labs.openai.com/s/${img}" target = "_blank" rel = "noreferrer" class = "${styles.modalImageContainerSquare}" >
< span class = "${styles.imgLoading}" > Loading cute image . . . < / span >
< img src = "https://openai-labs-public-images-prod.azureedge.net/user-jomUNcw4rd0bDGfcOQUAbYNO/generations/generation-${img}/image.webp" alt = "Incredibly cute AI created image of a penguin and a rabbit." / >
< / a >
< small > < i > Made with DALL - E < / i > < / small > ` );
2022-07-30 15:59:19 +02:00
cmdIf . callbacks . setModalVisible ( true ) ;
}
2022-07-30 15:45:09 +02:00
return [ "<3" ] ;
} ,
hidden : true
} ;
const blahaj : Command = {
name : "blahaj" ,
desc : "Blahaj is the best." ,
execute : ( ) = > {
2022-07-30 15:59:19 +02:00
setColors ( Color ( "#417988" ) ) ;
2022-07-30 15:45:09 +02:00
return [ " _________ . ." ,
"(.. \\_ , |\\ /|" ,
" \\ O \\ /| \\ \\/ / " ,
" \\______ \\/ | \\ / " ,
" vvvv\\ \\ | / |" ,
" \\^^^^ == \\_/ |" ,
" `\\_ === \\. |" ,
" / /\\_ \\ / |" ,
" |/ \\_ \\| /" ,
" \\________/" ] ;
} ,
hidden : true
} ;
const ping : Command = {
name : "ping" ,
desc : "Ping!" ,
execute : ( ) = > {
return [ "Pong!" ] ;
} ,
} ;
2022-08-23 10:10:45 +02:00
const jeb_ : Command = {
name : "jeb_" ,
desc : "🐑🌈" ,
execute : ( ) = > {
Rainbow . start ( ) ;
return [ ] ;
} ,
hidden : true
} ;
export const commandList = [ about , help , man , project , exitCmd , clear , color , save , pingi , blahaj , ping , jeb_ ] . sort ( ( a , b ) = > a . name . localeCompare ( b . name ) ) ;