diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index b58b603..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 25719e5..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index dcca0ed..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/sador.dev.iml b/.idea/sador.dev.iml deleted file mode 100644 index 24643cc..0000000 --- a/.idea/sador.dev.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/assets/script.js b/assets/script.js deleted file mode 100644 index 147531b..0000000 --- a/assets/script.js +++ /dev/null @@ -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'); -} \ No newline at end of file diff --git a/assets/style.css b/assets/style.css deleted file mode 100644 index fb78505..0000000 --- a/assets/style.css +++ /dev/null @@ -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; -} diff --git a/assets/style.dark.css b/assets/style.dark.css deleted file mode 100644 index d91aa58..0000000 --- a/assets/style.dark.css +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/assets/style.mobile.css b/assets/style.mobile.css deleted file mode 100644 index ccea640..0000000 --- a/assets/style.mobile.css +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..01edf81 --- /dev/null +++ b/css/style.css @@ -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; +} \ No newline at end of file diff --git a/css/style.dark.css b/css/style.dark.css new file mode 100644 index 0000000..41b41a0 --- /dev/null +++ b/css/style.dark.css @@ -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; +} \ No newline at end of file diff --git a/icons/github.png b/icons/github.png deleted file mode 100644 index 9490ffc..0000000 Binary files a/icons/github.png and /dev/null differ diff --git a/icons/instagram.png b/icons/instagram.png deleted file mode 100644 index 3146658..0000000 Binary files a/icons/instagram.png and /dev/null differ diff --git a/icons/youtube.png b/icons/youtube.png deleted file mode 100644 index c3bd27f..0000000 Binary files a/icons/youtube.png and /dev/null differ diff --git a/index.copy.html b/index.copy.html new file mode 100644 index 0000000..5b898ec --- /dev/null +++ b/index.copy.html @@ -0,0 +1,227 @@ + + + + + + + + + + + + sador + + + +
+
+

sador

+

? years old boy, who loves to code.

+ +

my hobbies

+ + +

my profiles

+ + +

contact

+ + +

go to section:

+ + +

go to top

+

switch theme

+
+
+
+
+

my projects

+ + +

my music taste

+

i'm a fan of:

+ + +

i enjoy these artists, but I can't say I'm a fan:

+ + +

i recently started to listen to:

+ + +

my hardware

+ + +

my software

+ + +

plans

+

i want to:

+ +
+
+ +
+
+
+
+ + + diff --git a/index.html b/index.html index 5dfe566..346c3f0 100644 --- a/index.html +++ b/index.html @@ -1,227 +1,30 @@ - - - - - - - - - - - - sador - - - -
-
-

sador

-

? years old boy, who loves to code.

- -

my hobbies

- - -

my profiles

- - -

contact

- - -

go to section:

- - -

go to top

-

switch theme

-
-
-
-
-

my projects

- - -

my music taste

-

i'm a fan of:

- - -

i enjoy these artists, but I can't say I'm a fan:

- - -

i recently started to listen to:

- - -

my hardware

- - -

my software

- - -

plans

-

i want to:

- -
-
- -
-
-
-
- - - + + + + + + + + + + + + + sador + + +
+

welcome to my website

+

switch theme

+ +

press Enter to run command

+

use 'help' to list all commands

+ + [guest@website ~]$ + +
+ +
+
+ + \ No newline at end of file diff --git a/js/commands.js b/js/commands.js new file mode 100644 index 0000000..f39fd82 --- /dev/null +++ b/js/commands.js @@ -0,0 +1,191 @@ +const COMMANDS = [ + { + name: 'help', + description: 'shows list of all commands', + usage: '', + 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: '', + 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]) => `${name}`) + .join('\n') + }, + { + name: 'curl', + description: 'open website in new tab', + usage: '', + 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')} + ` +} \ No newline at end of file diff --git a/js/data.js b/js/data.js new file mode 100644 index 0000000..000d946 --- /dev/null +++ b/js/data.js @@ -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' + ] +} \ No newline at end of file diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..8dd9c6f --- /dev/null +++ b/js/script.js @@ -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') \ No newline at end of file