Compare commits
2 Commits
69de1a5001
...
5e3c51e6be
Author | SHA1 | Date | |
---|---|---|---|
5e3c51e6be | |||
db91653f97 |
Binary file not shown.
Before Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 175 KiB |
Binary file not shown.
Before Width: | Height: | Size: 72 KiB |
BIN
assets/palette.png
Normal file
BIN
assets/palette.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
120
css/style.css
120
css/style.css
@ -6,15 +6,12 @@
|
|||||||
--color: #000;
|
--color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
color: var(--color);
|
color: var(--color);
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
font-family: 'Inconsolata', sans-serif;
|
font-family: 'Inconsolata', sans-serif;
|
||||||
@ -22,92 +19,49 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
display: flex;
|
max-width: 50%;
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#container>* {
|
#shadow {
|
||||||
width: 50%;
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
box-shadow: 0 0 30em 10em rgb(114, 114, 114);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-tooltip] {
|
.tags {
|
||||||
|
gap: 5px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags>* {
|
||||||
|
border: 2px solid var(--color);
|
||||||
|
padding: 10px 20px 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#switch_theme {
|
||||||
|
cursor: pointer;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
margin: 10px;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid var(--color);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-tooltip]:hover:after {
|
#switch_theme > img {
|
||||||
content: " (" attr(data-tooltip) ")";
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--color);
|
color: var(--color);
|
||||||
}
|
|
||||||
|
|
||||||
ul.vertical li {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.vertical li:not(:first-child)::before {
|
|
||||||
content: " - ";
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
a,
|
|
||||||
#result {
|
|
||||||
transition: background 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
font-family: 'Inconsolata', sans-serif;
|
|
||||||
font-size: 150%;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid;
|
|
||||||
|
|
||||||
color: var(--color);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
#result {
|
|
||||||
background-color: transparent;
|
|
||||||
white-space: preserve;
|
|
||||||
color: var(--color);
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
align-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#switch_theme,
|
|
||||||
#help {
|
|
||||||
text-decoration: underline;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-grid>* {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 798px) {
|
|
||||||
#container {
|
|
||||||
flex-direction: column !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container>* {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -10,4 +10,24 @@ body.dark input {
|
|||||||
body.dark #result,
|
body.dark #result,
|
||||||
body.dark a {
|
body.dark a {
|
||||||
color: var(--background) !important;
|
color: var(--background) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark .tags > * {
|
||||||
|
border: 2px solid var(--background);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark #shadow {
|
||||||
|
box-shadow: 0 0 30em 10em rgb(161, 148, 147);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark a {
|
||||||
|
color: var(--background);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark #switch_theme {
|
||||||
|
border: 1px solid var(--background) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark #switch_theme > img {
|
||||||
|
filter: invert() !important;
|
||||||
}
|
}
|
@ -7,10 +7,11 @@
|
|||||||
|
|
||||||
<link rel="shortcut icon" href="assets/logo.png">
|
<link rel="shortcut icon" href="assets/logo.png">
|
||||||
<link rel="stylesheet" href="css/style.css">
|
<link rel="stylesheet" href="css/style.css">
|
||||||
<title>sador - something weird happened</title>
|
<title>something weird happened</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="shadow"></div>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<h1 id="code">{{placeholder "http.error.status_code"}}</h1>
|
<h1 id="code">{{placeholder "http.error.status_code"}}</h1>
|
||||||
<p id="explanation">{{placeholder "http.error.message"}}.</p>
|
<p id="explanation">{{placeholder "http.error.message"}}.</p>
|
||||||
|
98
index.html
98
index.html
@ -5,27 +5,101 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<script src="js/commands.js" defer></script>
|
<script src="script.js" defer></script>
|
||||||
<script src="js/script.js" defer></script>
|
|
||||||
<script src="js/data.js" defer></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/style.css">
|
<link rel="stylesheet" href="css/style.css">
|
||||||
<link rel="icon" href="assets/logo.png">
|
<link rel="icon" href="assets/logo.png">
|
||||||
<title>sador</title>
|
<title>hi</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="shadow"></div>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div>
|
<h1>hi</h1>
|
||||||
<h1>welcome to my website</h1>
|
<h3>who i am</h3>
|
||||||
<h2 id="switch_theme">switch theme</h2>
|
<div class="tags">
|
||||||
|
<span>Franek</span>
|
||||||
<p>type <span id="help">'help'</span> to list all commands</p>
|
<span><span id="age">???</span> years old</span>
|
||||||
<span>[guest@website ~]$ </span>
|
<span>introvert</span>
|
||||||
<input type="text" id="command">
|
|
||||||
</div>
|
</div>
|
||||||
<div id="result">
|
|
||||||
|
|
||||||
|
<h3>what are my hobbies</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<span>IT</span>
|
||||||
|
<span>old automotive</span>
|
||||||
|
<span>music</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>what i can</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<span>play keyboard instruments</span>
|
||||||
|
<span>mess with PCs from software to hardware</span>
|
||||||
|
<span>program various apps and scripts</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>what music genres do I like</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<span>black metal</span>
|
||||||
|
<span>depressive suicidal black metal</span>
|
||||||
|
<span>doom metal</span>
|
||||||
|
<span>nu metal</span>
|
||||||
|
<span>rock</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>what bands/singers do I like</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<span>Mgła</span>
|
||||||
|
<span>Behemoth</span>
|
||||||
|
<span>Burzum</span>
|
||||||
|
<span>Venom</span>
|
||||||
|
<span>Darkthrone</span>
|
||||||
|
<span>Ancient North</span>
|
||||||
|
<span>Rammstein</span>
|
||||||
|
<span>None</span>
|
||||||
|
<span>Decalius</span>
|
||||||
|
<span>Slipknot</span>
|
||||||
|
<span>Lil Peep</span>
|
||||||
|
<span>ABBA</span>
|
||||||
|
<span>Alphaville</span>
|
||||||
|
<span>MGMT</span>
|
||||||
|
<span>Depeche Mode</span>
|
||||||
|
<span>Evanescence</span>
|
||||||
|
<span>Loreen</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>on which platforms I am on</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<a href="https://instagram.com/sadorowo">instagram</a>
|
||||||
|
<a href="https://github.com/sadorowo">github</a>
|
||||||
|
<a href="https://git.sador.me/sadorowo">gitea</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>what tools/frameworks do I know</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<span>React</span>
|
||||||
|
<span>Flutter</span>
|
||||||
|
<span>JavaScript</span>
|
||||||
|
<span>TypeScript</span>
|
||||||
|
<span>Rust</span>
|
||||||
|
<span>Go</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>what software I'm using</h3>
|
||||||
|
<div class="tags">
|
||||||
|
<span>Arch Linux + Hyprland</span>
|
||||||
|
<span>Firefox</span>
|
||||||
|
<span>VSCodium</span>
|
||||||
|
<span>YouTube Music</span>
|
||||||
|
<span>LibreOffice</span>
|
||||||
|
<span>Thunderbird</span>
|
||||||
|
</div>
|
||||||
|
<a href="mailto:contact@sador.me">
|
||||||
|
<h3>write a letter to me</h3>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h4>maybe i'll write something interesting here soon. who knows.</h4>
|
||||||
|
<div id="switch_theme">
|
||||||
|
<img src="assets/palette.png" alt="palette logo">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
193
js/commands.js
193
js/commands.js
@ -1,193 +0,0 @@
|
|||||||
const COMMANDS = [
|
|
||||||
{
|
|
||||||
name: 'help',
|
|
||||||
description: 'shows list of all commands',
|
|
||||||
usage: '<command?>',
|
|
||||||
usage_examples: ['help help', 'help music'],
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'command',
|
|
||||||
description: 'command name',
|
|
||||||
required: false,
|
|
||||||
check: (command) => !!command && !COMMANDS.find(c => c.name === command)
|
|
||||||
? "invalid command"
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
output: (command) => !!command
|
|
||||||
? getCommandHelp(command.toLowerCase())
|
|
||||||
: COMMANDS
|
|
||||||
.map(c => `${c.name}: ${c.description}`)
|
|
||||||
.join('\n')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'music',
|
|
||||||
description: 'show information about my music taste',
|
|
||||||
usage: '<genre?>',
|
|
||||||
usage_examples: ['music heavy metal', 'music gothic metal', 'music'],
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'genre',
|
|
||||||
description: 'music genre',
|
|
||||||
required: false,
|
|
||||||
multiword: true,
|
|
||||||
check: (genre) => !!genre && !getGenre(genre)
|
|
||||||
? "no informations about this music genre, run 'music' command to find available genres"
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
output: (...partialGenre) => {
|
|
||||||
const genre = partialGenre.join(' ')
|
|
||||||
|
|
||||||
return !!genre
|
|
||||||
? getGenreHelp(genre)
|
|
||||||
: `
|
|
||||||
if you want to get more info about specific genre, use <b>music [name/alias]</b>
|
|
||||||
i am listening to these music genres:
|
|
||||||
|
|
||||||
${MUSIC_METADATA
|
|
||||||
.map(genre_data => !!genre_data.aliases?.length
|
|
||||||
? `${genre_data.name} (aliases: ${genre_data.aliases.join(', ')})`
|
|
||||||
: genre_data.name)
|
|
||||||
.join('\n')}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'hardware',
|
|
||||||
description: 'show information about my hardware',
|
|
||||||
usage: '',
|
|
||||||
usage_examples: ['hardware'],
|
|
||||||
arguments: [],
|
|
||||||
output: () => [
|
|
||||||
'cpu: intel i5-4590',
|
|
||||||
'gpu: radeon rx 5500 xt',
|
|
||||||
'bluetooth & wi-fi: fenvi t919',
|
|
||||||
'keyboard: microsoft all-in-one media keyboard',
|
|
||||||
'headphones: beats studio buds',
|
|
||||||
'display: lg m2450d',
|
|
||||||
'motherboard: asrock h97m pro4',
|
|
||||||
'ram: 16gb ddr3',
|
|
||||||
'ssd: adata 500gb'
|
|
||||||
].join('\n')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'software',
|
|
||||||
description: 'show information about my software',
|
|
||||||
usage: '',
|
|
||||||
usage_examples: ['software'],
|
|
||||||
arguments: [],
|
|
||||||
output: () => [
|
|
||||||
'recording/editing:',
|
|
||||||
'',
|
|
||||||
'gimp',
|
|
||||||
'davinci resolve',
|
|
||||||
'',
|
|
||||||
'programming/web dev.:',
|
|
||||||
'',
|
|
||||||
'vscodium',
|
|
||||||
'android studio',
|
|
||||||
'ssh in terminal',
|
|
||||||
'postman',
|
|
||||||
'git',
|
|
||||||
'internet:',
|
|
||||||
'firefox',
|
|
||||||
'',
|
|
||||||
'music - tidal',
|
|
||||||
'',
|
|
||||||
'other:',
|
|
||||||
'',
|
|
||||||
'bitwarden (self-hosted)',
|
|
||||||
'libreoffice'
|
|
||||||
].join('\n')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'plans',
|
|
||||||
description: 'show my plans',
|
|
||||||
usage: '',
|
|
||||||
usage_examples: ['plans'],
|
|
||||||
arguments: [],
|
|
||||||
output: () => [
|
|
||||||
'i want to:',
|
|
||||||
'',
|
|
||||||
'change style/look',
|
|
||||||
'have maximum privacy',
|
|
||||||
'forget about my past',
|
|
||||||
'be happy',
|
|
||||||
'be successful',
|
|
||||||
'meet some kind and respective people'
|
|
||||||
].join('\n')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'links',
|
|
||||||
description: 'show URLs related to me & my services',
|
|
||||||
usage: '',
|
|
||||||
usage_examples: ['links'],
|
|
||||||
arguments: [],
|
|
||||||
output: () => Object.entries(LINKS)
|
|
||||||
.map(([name, url]) => `<a href="${url}" target="_blank">${name}</a>`)
|
|
||||||
.join('\n')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'desktop',
|
|
||||||
description: 'Show some desktop screenshots',
|
|
||||||
usage: '',
|
|
||||||
usage_examples: [],
|
|
||||||
arguments: [],
|
|
||||||
output: () => {
|
|
||||||
let result = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < 3;) {
|
|
||||||
result.push(`<img src="assets/desktop_screenshots/${++i}.png" alt="Desktop screenshot"/>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return `
|
|
||||||
<div class="image-grid">
|
|
||||||
${result.join('\n')}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
function getGenreHelp(genreName) {
|
|
||||||
const genre = getGenre(genreName)
|
|
||||||
|
|
||||||
if (!genre) return 'music: no informations about this music genre';
|
|
||||||
|
|
||||||
return `
|
|
||||||
i enjoy listening to ${genre.name}.
|
|
||||||
example ${genreName} artists/bands that i am listening to:
|
|
||||||
|
|
||||||
${genre.artists.join('\n')}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGenre(genreName) {
|
|
||||||
return MUSIC_METADATA.find(genre =>
|
|
||||||
genre.name === genreName ||
|
|
||||||
genre.aliases.includes(genreName));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCommandHelp(commandName) {
|
|
||||||
const command = COMMANDS.find(c => c.name === commandName)
|
|
||||||
|
|
||||||
if (!command) return 'help: invalid command';
|
|
||||||
|
|
||||||
return `
|
|
||||||
-> ${command.name} command
|
|
||||||
|
|
||||||
${command.description}
|
|
||||||
|
|
||||||
usage:
|
|
||||||
${command.name} ${command.usage}
|
|
||||||
|
|
||||||
arguments:
|
|
||||||
${command.arguments
|
|
||||||
.map(a => `${a.required ? 'required: ' : ''}${a.name} - ${a.description}`)
|
|
||||||
.join('\n')}
|
|
||||||
|
|
||||||
examples:
|
|
||||||
${command.usage_examples.join('\n')}
|
|
||||||
`
|
|
||||||
}
|
|
41
js/data.js
41
js/data.js
@ -1,41 +0,0 @@
|
|||||||
const LINKS = {
|
|
||||||
'gitea': 'https://git.sador.me/sadorowo',
|
|
||||||
'instagram': 'https://instagram.com/sadorowo',
|
|
||||||
'matrix': 'https://matrix.sador.me',
|
|
||||||
'email': 'mailto:contact@sador.me',
|
|
||||||
}
|
|
||||||
|
|
||||||
const MUSIC_METADATA = [
|
|
||||||
{
|
|
||||||
name: 'heavy metal',
|
|
||||||
aliases: ['hm', 'heavy'],
|
|
||||||
artists: [
|
|
||||||
'Poisonblack',
|
|
||||||
'Metallica'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'depressive suicidal black metal',
|
|
||||||
aliases: ['dsbm'],
|
|
||||||
artists: [
|
|
||||||
'Totalselfhatred',
|
|
||||||
'Lifelover',
|
|
||||||
'минута агонии',
|
|
||||||
'Decalius'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'black metal',
|
|
||||||
aliases: ['bm', 'black'],
|
|
||||||
artists: [
|
|
||||||
'Behemoth',
|
|
||||||
'Venom',
|
|
||||||
'Mgła',
|
|
||||||
'Watain',
|
|
||||||
'Bathory',
|
|
||||||
'Carpathian Forest',
|
|
||||||
'Darkthrone',
|
|
||||||
'Rotting Christ'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
90
js/script.js
90
js/script.js
@ -1,90 +0,0 @@
|
|||||||
// update age
|
|
||||||
function updateAge() {
|
|
||||||
const difference = (Date.now() - 1182722400000) / (1000 * 60 * 60 * 24 * 365);
|
|
||||||
age.textContent = difference.toFixed(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// process command function
|
|
||||||
function processCommand(input) {
|
|
||||||
const [commandName, ...args] = input.split(' ') || [input]
|
|
||||||
const suppliedCommand = COMMANDS.find(c => c.name === commandName)
|
|
||||||
|
|
||||||
if (!suppliedCommand) {
|
|
||||||
result.textContent = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { arguments, output } = suppliedCommand;
|
|
||||||
for (const i in arguments) {
|
|
||||||
const argument = arguments[i]
|
|
||||||
|
|
||||||
if (argument.required && !args[i]) {
|
|
||||||
result.textContent = `argument ${argument.name} is missing`;
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const errorMessage = argument.check(argument.multiword ? args.join(' ') : args[i])
|
|
||||||
|
|
||||||
if (typeof errorMessage === 'string') {
|
|
||||||
result.textContent = `error while executing ${suppliedCommand.name}: ${errorMessage}`;
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.innerHTML = output(...args).replaceAll(TAB, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
// wrapper for setInterval
|
|
||||||
const runEvery = (task, ms) => {
|
|
||||||
task()
|
|
||||||
setInterval(task, ms)
|
|
||||||
}
|
|
||||||
|
|
||||||
// smooth scrolling
|
|
||||||
const smoothScrollLinks = document.querySelectorAll('a[href^="#"]');
|
|
||||||
smoothScrollLinks.forEach(link => {
|
|
||||||
link.addEventListener('click', event => {
|
|
||||||
event.preventDefault();
|
|
||||||
const target = document.querySelector(event.target.hash);
|
|
||||||
|
|
||||||
target.scrollIntoView({ behavior: 'smooth' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// theme management
|
|
||||||
switch_theme?.addEventListener('click', () => {
|
|
||||||
const theme = localStorage.getItem('theme');
|
|
||||||
|
|
||||||
localStorage.setItem('theme', theme === 'light' ? 'dark' : 'light');
|
|
||||||
document.body.classList.toggle('dark')
|
|
||||||
})
|
|
||||||
|
|
||||||
// command management
|
|
||||||
const TAB = ' ';
|
|
||||||
|
|
||||||
command?.addEventListener('focusout', () => {
|
|
||||||
setTimeout(() => command.focus(), 0);
|
|
||||||
})
|
|
||||||
|
|
||||||
command?.addEventListener('input', () => processCommand(command.value))
|
|
||||||
|
|
||||||
// run all tasks
|
|
||||||
if (typeof age !== 'undefined') runEvery(updateAge, 10 * 1000)
|
|
||||||
command?.focus()
|
|
||||||
|
|
||||||
// initial theme configuration
|
|
||||||
const theme = localStorage.getItem('theme');
|
|
||||||
if (theme === 'dark')
|
|
||||||
document.body.classList.add('dark')
|
|
||||||
|
|
||||||
// listen to help tooltip
|
|
||||||
help.addEventListener('click', () => {
|
|
||||||
command.value = 'help';
|
|
||||||
processCommand('help');
|
|
||||||
})
|
|
||||||
|
|
||||||
// ignore context menu
|
|
||||||
document.addEventListener('contextmenu', e => e.preventDefault());
|
|
||||||
|
|
||||||
// check for command in input
|
|
||||||
if (command?.value) processCommand(command.value);
|
|
35
script.js
Normal file
35
script.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// update age
|
||||||
|
function updateAge() {
|
||||||
|
const difference = new Date().getFullYear() - 2007;
|
||||||
|
age.textContent = difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
// smooth scrolling
|
||||||
|
const smoothScrollLinks = document.querySelectorAll('a[href^="#"]');
|
||||||
|
smoothScrollLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', event => {
|
||||||
|
event.preventDefault();
|
||||||
|
const target = document.querySelector(event.target.hash);
|
||||||
|
|
||||||
|
target.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// theme management
|
||||||
|
switch_theme?.addEventListener('click', () => {
|
||||||
|
const theme = localStorage.getItem('theme');
|
||||||
|
|
||||||
|
localStorage.setItem('theme', theme === 'light' ? 'dark' : 'light');
|
||||||
|
document.body.classList.toggle('dark')
|
||||||
|
})
|
||||||
|
|
||||||
|
// run all tasks
|
||||||
|
if (typeof age !== 'undefined') updateAge()
|
||||||
|
|
||||||
|
// initial theme configuration
|
||||||
|
const theme = localStorage.getItem('theme');
|
||||||
|
if (theme === 'dark')
|
||||||
|
document.body.classList.add('dark')
|
||||||
|
|
||||||
|
// ignore context menu
|
||||||
|
document.addEventListener('contextmenu', e => e.preventDefault());
|
Loading…
Reference in New Issue
Block a user