Compare commits

...

3 Commits

Author SHA1 Message Date
4e0bb508e6 merge v2 into main branch
Reviewed-on: #1
2024-04-20 14:17:52 +00:00
14f4757f5d
new error page 2024-04-20 16:16:26 +02:00
bd784fa0f9
complete website redesign 2024-04-20 16:13:46 +02:00
20 changed files with 662 additions and 482 deletions

5
.idea/.gitignore vendored
View File

@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -1,10 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="12" name="Style Sheets" />
</Languages>
</inspection_tool>
</profile>
</component>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/sador.dev.iml" filepath="$PROJECT_DIR$/.idea/sador.dev.iml" />
</modules>
</component>
</project>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,44 +0,0 @@
if (typeof age !== 'undefined') {
const difference = (Date.now() - 1182722400000) / (1000 * 60 * 60 * 24 * 365);
age.textContent = difference.toFixed(4);
}
if (typeof arrow_top !== 'undefined' && typeof arrow_bottom !== 'undefined') {
[arrow_top, arrow_bottom].forEach(arrow => {
arrow.addEventListener('click', () => {
console.warn('scroll!')
window.scrollTo({
top: arrow === arrow_top ? 0 : document.body.scrollHeight,
behavior: 'smooth'
});
});
});
}
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'
});
});
});
const theme = localStorage.getItem('theme');
switch_theme?.addEventListener('click', () => {
if (theme === 'dark') {
localStorage.setItem('theme', 'light');
} else {
localStorage.setItem('theme', 'dark');
}
document.body.classList.toggle('dark');
});
if (theme === 'dark') {
document.body.classList.add('dark');
}

View File

@ -1,98 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200..900&display=swap');
@import url('style.mobile.css');
@import url('style.dark.css');
:root {
--font: 'Inconsolata', monospace;
--font-size: 16px;
--columns: 2;
}
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
body {
font-family: var(--font);
font-size: var(--font-size);
transition: background-color 0.5s, color 0.5s;
}
body#centered {
display: grid;
place-items: center;
align-content: center;
}
body>div:not([id]) {
display: grid;
overflow-y: auto;
place-items: center;
align-content: center;
float: left;
height: 100%;
width: calc(100% / var(--columns));
}
body>div:first-child #arrow {
bottom: 0;
width: 100%;
display: none;
cursor: pointer;
color: #fff;
text-align: center;
background-color: black;
}
body>div>div#inner {
overflow-y: auto;
height: 100%;
}
ul {
padding: 0;
}
ul,
ol {
list-style-type: none;
}
ul li::before,
ol li::before {
content: "⮑ ";
}
#age {
font-weight: 900;
}
*[data-deprecated] {
text-decoration: line-through;
}
*[data-deprecated]::after {
content: ' (' attr(data-deprecated-entry, "deprecated") ')';
color: red;
}
#contact li:first-child::before {
content: "✉ ";
}
#switch_theme {
color: blue;
cursor: pointer;
text-decoration: underline;
}
body>#arrows {
display: none;
}

View File

@ -1,37 +0,0 @@
:root {
--font: 'Inconsolata', monospace;
--font-size: 16px;
--columns: 2;
--background-color: #171616;
--color: #fff;
}
body.dark {
background-color: var(--background-color);
color: var(--color);
}
body.dark>div:first-child #arrow {
color: #000;
text-align: center;
background-color: #fff;
}
body>div:first-child #arrow {
background-color: var(--color);
color: var(--background-color);
}
body.dark a {
color: var(--color);
}
body.dark #switch_theme {
color: var(--color);
}
body.dark>#arrows>div {
background-color: var(--color);
color: var(--background-color);
}

View File

@ -1,30 +0,0 @@
@media screen and (max-width: 767px) {
body>div:not([id]) {
height: unset !important;
width: 100% !important;
border-bottom: 1px solid;
}
body>div>div#inner {
overflow-y: hidden !important;
height: auto !important;
padding: 1em !important;
}
body>#arrows {
display: flex !important;
width: 100% !important;
position: fixed;
bottom: 0;
right: 0;
}
body>#arrows>div {
width: 50%;
text-align: center;
background-color: black;
color: white;
cursor: pointer;
}
}

82
css/style.css Normal file
View File

@ -0,0 +1,82 @@
@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200..900&display=swap');
@import url('style.dark.css');
:root {
--background: #fff;
--color: #000;
}
html,
body {
width: 100%;
height: 100%;
}
body {
margin: 0;
padding: 0;
color: var(--color);
background-color: var(--background);
font-family: 'Inconsolata', sans-serif;
transition: background 0.3s ease-in-out;
}
#container {
text-align: center;
height: 100%;
width: 100%;
align-content: center;
}
[data-tooltip] {
text-decoration: underline;
}
[data-tooltip]:hover:after {
content: " (" attr(data-tooltip) ")";
}
a {
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 {
white-space: preserve;
background-color: transparent;
color: var(--color);
padding: 2em;
margin: 2em;
}
#switch_theme {
text-decoration: underline;
cursor: pointer;
}

12
css/style.dark.css Normal file
View File

@ -0,0 +1,12 @@
body.dark {
color: var(--background) !important;
background-color: var(--color) !important;
}
body.dark input {
color: var(--background) !important;
}
body.dark #result, body.dark a {
color: var(--background) !important;
}

View File

@ -6,13 +6,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="assets/logo.png"> <link rel="shortcut icon" href="assets/logo.png">
<link rel="stylesheet" href="assets/style.css"> <link rel="stylesheet" href="css/style.css">
<title>sador - something weird happened</title> <title>sador - something weird happened</title>
</head> </head>
<body id="centered"> <body>
<h1 id="code">{{placeholder "http.error.status_code"}}</h1> <div id="container">
<p id="explanation">{{placeholder "http.error.message"}}.</p> <h1 id="code">{{placeholder "http.error.status_code"}}</h1>
<a onclick="history.back()">go back</a> <p id="explanation">{{placeholder "http.error.message"}}.</p>
<a onclick="history.back()">go back</a>
</div>
</body> </body>
</html> </html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

227
index.copy.html Normal file
View File

@ -0,0 +1,227 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="hii">
<link rel="shortcut icon" href="assets/logo.png">
<link rel="stylesheet" href="assets/style.css">
<script defer src="assets/script.js"></script>
<title>sador</title>
</head>
<body>
<div>
<div id="inner">
<h1>sador</h1>
<p><span id="age">?</span> years old boy, who loves to code.</p>
<h2>my hobbies</h2>
<ul>
<li>programming</li>
<li>music</li>
<li>old automotive</li>
</ul>
<h2>my profiles</h2>
<ul>
<li><a href="https://github.com/sadorowo" target="_blank" data-deprecated data-deprecated-entry="abandoned">github</a></li>
<li><a href="https://instagram.com/sadorowo" target="_blank">instagram</a></li>
<li><a href="https://photos.sador.me" target="_blank">immich</a></li>
<li><a href="https://git.sador.me/sadorowo" target="_blank">gitea</a></li>
</ul>
<h2>contact</h2>
<ul id="contact">
<li><a href="mailto:contact@sador.me">e-mail</a></li>
</ul>
<h3 id="sections">go to section:</h3>
<ul>
<li><a href="#projects">my projects</a></li>
<li><a href="#music-taste">my music taste</a></li>
<li><a href="#hardware">my hardware</a></li>
<li><a href="#software">my software</a></li>
<li><a href="#plans">plans</a></li>
</ul>
<h2><a href="#projects">go to top</a></h2>
<h2 id="switch_theme">switch theme</h2>
</div>
</div>
<div>
<div id="inner">
<h2 id="projects">my projects</h2>
<ul>
<li>
websites
<ol>
<li><a href="https://git.sador.me/sadorowo/personal-website"
target="_blank">sadorowo/personal-website</a></li>
<li><a href="https://git.sador.me/sadorowo/witch-website"
target="_blank">sadorowo/witch-website</a>
</li>
<li><a href="https://git.sador.me/sadorowo/draw" target="_blank">sadorowo/draw</a></li>
</ol>
</li>
<li>
projects
<ol>
<li><a href="https://git.sador.me/sadorowo/dynamic-content-delivery"
target="_blank">sadorowo/dynamic-content-delivery</a></li>
<li><a href="https://git.sador.me/sadorowo/dynamic-content-delivery-api"
target="_blank">sadorowo/dynamic-content-delivery-api</a></li>
<li data-deprecated><a href="https://git.sador.me/sadorowo/dcd-legacy"
target="_blank">sadorowo/dcd-legacy</a></li>
<li><a href="https://git.sador.me/sadorowo/wulkanowy-mod"
target="_blank">sadorowo/wulkanowy-mod</a>
</li>
<li><a href="https://git.sador.me/sadorowo/zine-v4" target="_blank"
data-deprecated>sadorowo/zine-v4</a></li>
</ol>
</li>
<li>
tools
<ol>
<li><a href="https://git.sador.me/sadorowo/m3u-category-matcher"
target="_blank">sadorowo/m3u-category-matcher</a>
</li>
<li><a href="https://git.sador.me/sadorowo/m3u-logo-matcher"
target="_blank">sadorowo/m3u-logo-matcher</a>
</li>
<li><a href="https://git.sador.me/sadorowo/m3u-duplicates-filter"
target="_blank">sadorowo/m3u-duplicates-filter</a></li>
</ol>
</li>
</ul>
<h2 id="music_taste">my music taste</h2>
<p>i'm a fan of:</p>
<ul>
<li>
genres
<ol>
<li>heavy metal</li>
<li>black metal</li>
<li>death metal</li>
<li>doom metal</li>
<li>hard rock</li>
</ol>
</li>
<li>
rock/metal bands/artists
<ol>
<li>Behemoth</li>
<li>Draconian</li>
<li>Poisonblack</li>
<li>To/Die/For</li>
<li>For My Pain...</li>
<li>Death</li>
<li>Charon</li>
<li>Entwine</li>
<li>Slipknot</li>
</ol>
</li>
</ul>
<p>i enjoy these artists, but I can't say I'm a fan:</p>
<ul>
<li>Lacrimas Profundere</li>
<li>Beseech</li>
<li>Darkthrone</li>
<li>Dark Funeral</li>
<li>Venom</li>
</ul>
<p>i recently started to listen to:</p>
<ul>
<li>Deathstars</li>
<li>Carpatian Forest</li>
<li>Gorgoroth</li>
<li>Immortal</li>
<li>Emperor</li>
<li>Imminence</li>
</ul>
<h2 id="hardware">my hardware</h2>
<ul>
<li>
OSes
<ol>
<li>arch linux (kde plasma)</li>
<li>degoogled android (lineageos)</li>
</ol>
</li>
<li>
in general
<ol>
<li>cpu: intel i5-4590</li>
<li>gpu: radeon rx 5500 xt</li>
<li>bluetooth & wi-fi: fenvi t919</li>
<li>keyboard: microsoft all-in-one media keyboard</li>
<li>headphones: beats studio buds</li>
<li>display: lg m2450d</li>
<li>motherboard: asrock h97m pro4</li>
<li>ram: 16gb ddr3</li>
<li>ssd: adata 500gb</li>
</ol>
</li>
</ul>
<h2 id="software">my software</h2>
<ul>
<li>
recording/editing
<ol>
<li>gimp</li>
<li>davinci resolve</li>
</ol>
</li>
<li>
programming/web dev.
<ol>
<li>vscodium</li>
<li>android studio</li>
<li>ssh in terminal</li>
<li>postman</li>
<li>git</li>
</ol>
</li>
<li>
internet
<ol>
<li>firefox</li>
</ol>
</li>
<li>music - tidal</li>
<li>
other
<ol>
<li>bitwarden (self-hosted)</li>
<li>libreoffice</li>
</ol>
</li>
</ul>
<h2 id="plans">plans</h2>
<p>i want to:</p>
<ul>
<li>change style/look</li>
<li>have maximum privacy</li>
<li>forget about my past</li>
<li>be happy</li>
<li>be successful</li>
<li>meet some kind and respective people</li>
</ul>
</div>
</div>
<div id="arrows">
<div id="arrow_top"></div>
<div id="arrow_bottom"></div>
</div>
</body>
</html>

View File

@ -1,227 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="pl"> <html lang="en">
<head>
<head> <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">
<meta name="description" content="hii"> <script src="js/commands.js" defer></script>
<script src="js/script.js" defer></script>
<link rel="shortcut icon" href="assets/logo.png"> <script src="js/data.js" defer></script>
<link rel="stylesheet" href="assets/style.css">
<script defer src="assets/script.js"></script> <link rel="stylesheet" href="css/style.css">
<title>sador</title> <link rel="icon" href="assets/logo.png">
</head> <title>sador</title>
</head>
<body> <body>
<div> <div id="container">
<div id="inner"> <h1>welcome to my website</h1>
<h1>sador</h1> <h2 id="switch_theme">switch theme</h2>
<p><span id="age">?</span> years old boy, who loves to code.</p>
<p>press <kbd>Enter</kbd> to run command</p>
<h2>my hobbies</h2> <p>use 'help' to list all commands</p>
<ul>
<li>programming</li> <span>[guest@website ~]$ </span>
<li>music</li> <input type="text" id="command" value="help">
<li>old automotive</li> <div id="result">
</ul>
</div>
<h2>my profiles</h2> </div>
<ul> </body>
<li><a href="https://github.com/sadorowo" target="_blank" data-deprecated data-deprecated-entry="abandoned">github</a></li> </html>
<li><a href="https://instagram.com/sadorowo" target="_blank">instagram</a></li>
<li><a rel="me" href="https://photos.sador.me">immich</a></li>
<li><a href="https://git.sador.me/sadorowo">gitea</a></li>
</ul>
<h2>contact</h2>
<ul id="contact">
<li><a href="mailto:contact@sador.me">e-mail</a></li>
</ul>
<h3 id="sections">go to section:</h3>
<ul>
<li><a href="#projects">my projects</a></li>
<li><a href="#music-taste">my music taste</a></li>
<li><a href="#hardware">my hardware</a></li>
<li><a href="#software">my software</a></li>
<li><a href="#plans">plans</a></li>
</ul>
<h2><a href="#projects">go to top</a></h2>
<h2 id="switch_theme">switch theme</h2>
</div>
</div>
<div>
<div id="inner">
<h2 id="projects">my projects</h2>
<ul>
<li>
websites
<ol>
<li><a href="https://git.sador.me/sadorowo/personal-website"
target="_blank">sadorowo/personal-website</a></li>
<li><a href="https://git.sador.me/sadorowo/witch-website"
target="_blank">sadorowo/witch-website</a>
</li>
<li><a href="https://git.sador.me/sadorowo/draw" target="_blank">sadorowo/draw</a></li>
</ol>
</li>
<li>
projects
<ol>
<li><a href="https://git.sador.me/sadorowo/dynamic-content-delivery"
target="_blank">sadorowo/dynamic-content-delivery</a></li>
<li><a href="https://git.sador.me/sadorowo/dynamic-content-delivery-api"
target="_blank">sadorowo/dynamic-content-delivery-api</a></li>
<li data-deprecated><a href="https://git.sador.me/sadorowo/dcd-legacy"
target="_blank">sadorowo/dcd-legacy</a></li>
<li><a href="https://git.sador.me/sadorowo/wulkanowy-mod"
target="_blank">sadorowo/wulkanowy-mod</a>
</li>
<li><a href="https://git.sador.me/sadorowo/zine-v4" target="_blank"
data-deprecated>sadorowo/zine-v4</a></li>
</ol>
</li>
<li>
tools
<ol>
<li><a href="https://git.sador.me/sadorowo/m3u-category-matcher"
target="_blank">sadorowo/m3u-category-matcher</a>
</li>
<li><a href="https://git.sador.me/sadorowo/m3u-logo-matcher"
target="_blank">sadorowo/m3u-logo-matcher</a>
</li>
<li><a href="https://git.sador.me/sadorowo/m3u-duplicates-filter"
target="_blank">sadorowo/m3u-duplicates-filter</a></li>
</ol>
</li>
</ul>
<h2 id="music_taste">my music taste</h2>
<p>i'm a fan of:</p>
<ul>
<li>
genres
<ol>
<li>heavy metal</li>
<li>black metal</li>
<li>death metal</li>
<li>doom metal</li>
<li>hard rock</li>
</ol>
</li>
<li>
rock/metal bands/artists
<ol>
<li>Behemoth</li>
<li>Draconian</li>
<li>Poisonblack</li>
<li>To/Die/For</li>
<li>For My Pain...</li>
<li>Death</li>
<li>Charon</li>
<li>Entwine</li>
<li>Slipknot</li>
</ol>
</li>
</ul>
<p>i enjoy these artists, but I can't say I'm a fan:</p>
<ul>
<li>Lacrimas Profundere</li>
<li>Beseech</li>
<li>Darkthrone</li>
<li>Dark Funeral</li>
<li>Venom</li>
</ul>
<p>i recently started to listen to:</p>
<ul>
<li>Deathstars</li>
<li>Carpatian Forest</li>
<li>Gorgoroth</li>
<li>Immortal</li>
<li>Emperor</li>
<li>Imminence</li>
</ul>
<h2 id="hardware">my hardware</h2>
<ul>
<li>
OSes
<ol>
<li>arch linux (kde plasma)</li>
<li>degoogled android (lineageos)</li>
</ol>
</li>
<li>
in general
<ol>
<li>cpu: intel i5-4590</li>
<li>gpu: radeon rx 5500 xt</li>
<li>bluetooth & wi-fi: fenvi t919</li>
<li>keyboard: microsoft all-in-one media keyboard</li>
<li>headphones: beats studio buds</li>
<li>display: lg m2450d</li>
<li>motherboard: asrock h97m pro4</li>
<li>ram: 16gb ddr3</li>
<li>ssd: adata 500gb</li>
</ol>
</li>
</ul>
<h2 id="software">my software</h2>
<ul>
<li>
recording/editing
<ol>
<li>gimp</li>
<li>davinci resolve</li>
</ol>
</li>
<li>
programming/web dev.
<ol>
<li>vscodium</li>
<li>android studio</li>
<li>ssh in terminal</li>
<li>postman</li>
<li>git</li>
</ol>
</li>
<li>
internet
<ol>
<li>firefox</li>
</ol>
</li>
<li>music - tidal</li>
<li>
other
<ol>
<li>bitwarden (self-hosted)</li>
<li>libreoffice</li>
</ol>
</li>
</ul>
<h2 id="plans">plans</h2>
<p>i want to:</p>
<ul>
<li>change style/look</li>
<li>have maximum privacy</li>
<li>forget about my past</li>
<li>be happy</li>
<li>be successful</li>
<li>meet some kind and respective people</li>
</ul>
</div>
</div>
<div id="arrows">
<div id="arrow_top"></div>
<div id="arrow_bottom"></div>
</div>
</body>
</html>

191
js/commands.js Normal file
View File

@ -0,0 +1,191 @@
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)
: 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 && !Object.keys(MUSIC_METADATA).includes(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)
: `
i am listening to these music genres:
${Object.keys(MUSIC_METADATA)
.map(genre => `${genre} - more info: 'music ${genre}'`)
.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: 'curl',
description: 'open website in new tab',
usage: '<website>',
usage_examples: ['curl google.com'],
arguments: [
{
name: 'url',
description: 'URL to open',
required: true,
multiword: true,
check: (url) => URL_REGEX.test(url)
? null
: "invalid URL"
}
],
output: (url) => {
Object.assign(document.createElement('a'), {
target: '_blank',
rel: 'noopener noreferrer',
href: url,
}).click();
return ''
}
}
]
function getGenreHelp(genreName) {
const genre = MUSIC_METADATA[genreName];
if (!genre) return 'music: no informations about this music genre';
return `
i enjoy listening to ${genreName}.
example ${genreName} artists/bands that i am listening to:
${genre.join('\n')}
`
}
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')}
`
}

36
js/data.js Normal file
View File

@ -0,0 +1,36 @@
const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
const LINKS = {
'gitea': 'https://git.sador.me',
'instagram': 'https://instagram.com/sadorowo',
'immich': 'https://photos.sador.me/',
'email': 'mailto:contact@sador.me'
}
const MUSIC_METADATA = {
'heavy metal': [
'Poisonblack',
'Metallica'
],
'gothic metal': [
'Draconian',
'Beseech',
'To/Die/For',
'For My Pain...',
'Charon',
'Entwine'
],
'death suicidal black metal': [
'minuta agonii',
'Decalius'
],
'black metal': [
'Behemoth',
'Venom',
'Carpathian Forest',
'Darkthrone'
],
'nu metal': [
'Slipknot',
'Evanescence'
]
}

77
js/script.js Normal file
View File

@ -0,0 +1,77 @@
// update age
function updateAge() {
const difference = (Date.now() - 1182722400000) / (1000 * 60 * 60 * 24 * 365);
age.textContent = difference.toFixed(4);
}
// 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('keydown', e => {
if (e.key === 'Enter') {
const [commandName, ...args] = e.target.value.split(' ') || [e.target.value]
const command = COMMANDS.find(c => c.name === commandName)
if (!command) {
result.textContent = 'invalid command';
return
}
const { arguments, output } = command;
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 ${command.name}: ${errorMessage}`;
return
}
}
result.innerHTML = output(...args).replaceAll(TAB, '')
}
})
// 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')