mirror of
https://github.com/danbulant/design
synced 2026-06-17 13:21:30 +00:00
improve code readability, replace igni with tictactoe
This commit is contained in:
parent
8809c92b40
commit
4e883e3f7e
37 changed files with 461 additions and 478 deletions
|
|
@ -6,6 +6,7 @@ The home page, hosted on cloudflare pages. Made with Svelte, SvelteKit and mdsve
|
|||
|
||||
The code for the website and it's styles is licensed under AGPLv3 (see LICENSE file).
|
||||
Files in `static` are subject to their own copyright terms:
|
||||
|
||||
- `posts` folder is available under the same terms as the post in which they appear, or if they have their own LICENSE file in the same location (named `image.LICENSE` where `image` is the filename of the image)
|
||||
- `prism` files have their own copyright on top of the file and are available under MIT license
|
||||
- `screenshots` are under CC-BY-SA, except for `igni.png` and `mangadex.jfif` which are both copyrighted to their respective owners.
|
||||
|
|
@ -21,4 +22,4 @@ Files in `static` are subject to their own copyright terms:
|
|||
## Attributions
|
||||
|
||||
- Heaventaker (`static/screenshots/heaventaker.png`) - CC-BY-SA u/hohodo, Daniel Bulant (part of the Heaventaker project)
|
||||
- design by Carl Hansen
|
||||
- Original design by Carl Hansen, heavily edited.
|
||||
|
|
|
|||
|
|
@ -4,15 +4,11 @@ import fs from "fs";
|
|||
export const prettyCode = createRemarkPlugin({
|
||||
// Options passed to shiki.getHighlighter()
|
||||
shikiOptions: {
|
||||
// Link to your VS Code theme JSON file
|
||||
theme: JSON.parse(
|
||||
fs.readFileSync("./shiki/themes/OneDark.json", "utf-8")
|
||||
),
|
||||
},
|
||||
// These are hooks which allow you to style the node. `node` is an element
|
||||
// using JSDOM, so you can apply any CSS.
|
||||
onVisitLine(node) {
|
||||
// Style a line node.
|
||||
node.innerHTML = node.innerHTML
|
||||
.replace(/{/g, "{")
|
||||
.replace(/}/g, "}");
|
||||
|
|
@ -22,13 +18,11 @@ export const prettyCode = createRemarkPlugin({
|
|||
});
|
||||
},
|
||||
onVisitHighlightedLine(node) {
|
||||
// Style a highlighted line node.
|
||||
Object.assign(node.style, {
|
||||
backgroundColor: "rgba(0,0,0,0.1)",
|
||||
});
|
||||
},
|
||||
onVisitHighlightedWord(node) {
|
||||
// Style a highlighted word node.
|
||||
Object.assign(node.style, {
|
||||
backgroundColor: "rgba(0,0,0,0.5)",
|
||||
padding: "0.25rem",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
import { visit } from "unist-util-visit"
|
||||
|
||||
// Allows having highlight in blog posts.
|
||||
|
||||
// Very fun, debugging this stuff..
|
||||
// Dirty, but it works.
|
||||
|
||||
// It has the unescape characters because sveltemdx escapes them. It doesn't do that when we use their highlighter - but that
|
||||
// one doesn't support inline code.
|
||||
// So we have to unescape those characters back to how they were before, but then escape them again because svelte
|
||||
// would understand certain characters (namely {}. For some reason, `<>` was fine.) as svelte code.
|
||||
|
||||
export function remarkUnescapeHighlight() {
|
||||
return (tree, file) => {
|
||||
visit(tree, ["code"], (node) => {
|
||||
|
|
|
|||
|
|
@ -5,16 +5,11 @@ var apm_: ApmBase;
|
|||
|
||||
if(browser) {
|
||||
apm_ = initApm({
|
||||
// Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)
|
||||
// allowed characters: a-z, A-Z, 0-9, -, _, and space
|
||||
serviceName: 'homepage',
|
||||
|
||||
// Set custom APM Server URL (default: http://localhost:8200)
|
||||
serverUrl: 'https://apm.elasticsearch.danbulant.cloud',
|
||||
|
||||
// Set the service version (required for source map feature)
|
||||
// for source maps, but those are not implemented in this project
|
||||
serviceVersion: import.meta.env.VITE_SENTRY_RELEASE,
|
||||
|
||||
// Set the service environment
|
||||
environment: import.meta.env.VITE_SENTRY_ENVIRONMENT || 'production'
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
<script>
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
import Bar from "./bar.svelte";
|
||||
import Split from "./split.svelte";
|
||||
</script>
|
||||
|
||||
<div class="bottombar" class:dark={$darkmode}>
|
||||
<div class="bottombar">
|
||||
<Bar>
|
||||
<h3>Daniel Bulant</h3>
|
||||
<Split />
|
||||
|
|
@ -29,7 +28,7 @@
|
|||
width: 100%;
|
||||
background: white;
|
||||
}
|
||||
.dark.bottombar {
|
||||
:global(.dark) .bottombar {
|
||||
background: rgb(28, 28, 33);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +40,7 @@
|
|||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
.dark h3 {
|
||||
:global(.dark) h3 {
|
||||
color: rgb(191, 191, 191);
|
||||
}
|
||||
h3 {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
<script>
|
||||
import darkmode from "../stores/darkmode";
|
||||
|
||||
export var href = "";
|
||||
export var text = false;
|
||||
export var blur = false;
|
||||
|
|
@ -10,12 +8,12 @@
|
|||
</script>
|
||||
|
||||
{#if href}
|
||||
<a href={href} class:blur tabindex="0" class="button {className}" class:text class:dark={$darkmode}><slot /></a>
|
||||
<a href={href} class:blur tabindex="0" class="button {className}" class:text><slot /></a>
|
||||
{:else}
|
||||
<button class="button {className}" class:blur on:click class:text class:dark={$darkmode}><slot /></button>
|
||||
<button class="button {className}" class:blur on:click class:text><slot /></button>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
|
||||
.button {
|
||||
@apply bg-black/50 rounded;
|
||||
|
|
@ -34,14 +32,14 @@
|
|||
background: transparent;
|
||||
color: black;
|
||||
}
|
||||
.dark.text {
|
||||
:global(.dark) .text {
|
||||
color: white;
|
||||
}
|
||||
.button:hover, .button:focus {
|
||||
text-decoration: none;
|
||||
border-color: black;
|
||||
}
|
||||
.button.dark:hover, .button.dark:focus {
|
||||
:global(.dark) .button:hover, :global(.dark) .button:focus {
|
||||
border-color: white;
|
||||
}
|
||||
.button {
|
||||
|
|
|
|||
|
|
@ -54,16 +54,13 @@
|
|||
<span class="name">@danbulant</span>
|
||||
</div>
|
||||
</a>
|
||||
<div>
|
||||
<a use:goatCounter data-goatcounter-click="contact-layer8" href="https://layer8.space/@techmandan">
|
||||
<span class="platform">Mastodon</span>
|
||||
<div class="main">
|
||||
<img src="/tech/mastodon.png" alt="" draggable={false}>
|
||||
<div class="flex flex-col">
|
||||
<!-- <a rel="me" use:goatCounter data-goatcounter-click="contact-mastodon" href="https://mastodon.social/danbulant" class="name !hover:underline">@danbulant@mastodon.social</a> -->
|
||||
<a rel="me" use:goatCounter data-goatcounter-click="contact-layer8" href="https://layer8.space/@techmandan" class="name !hover:underline">@techmandan@layer8.space</a>
|
||||
</div>
|
||||
<a rel="me" use:goatCounter data-goatcounter-click="contact-layer8" href="https://layer8.space/@techmandan" class="name !hover:underline">@techmandan@layer8.space</a>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="mailto:me@danbulant.eu" use:goatCounter data-goatcounter-click="contact-email">
|
||||
<span class="platform">Email</span>
|
||||
<div class="main">
|
||||
|
|
@ -72,7 +69,14 @@
|
|||
</div>
|
||||
</a>
|
||||
<div>
|
||||
<div class="platform">Time</div>
|
||||
<span class="platform">Matrix</span>
|
||||
<div class="main">
|
||||
<span class="logo">[]</span>
|
||||
<span class="name">@/:danbulant.cz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="platform">Local Time</div>
|
||||
<div class="main">
|
||||
<img src="/tech/clock.svg" alt="" draggable={false}>
|
||||
<div class="name">GMT+1 - {time.setZone("Europe/Prague", { keepLocalTime: true }).toFormat("HH:mm:ss")}</div>
|
||||
|
|
@ -104,8 +108,10 @@
|
|||
.profiles > div {
|
||||
@apply m-0 p-0;
|
||||
}
|
||||
img {
|
||||
img, .logo {
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -18,19 +18,16 @@
|
|||
</script>
|
||||
|
||||
<div class="hero">
|
||||
<div class="bg z-0">
|
||||
<img class="bg1" style="right: {(current - 3) * 100}%;" src="/screenshots/heaventaker/heaventaker.webp" alt="">
|
||||
<img class="bg2" style="right: {(current - 2) * 100}%;" src="/screenshots/animasher.webp" alt="">
|
||||
<img class="bg3" style="right: {(current - 1) * 100}%;" src="/screenshots/ignibg.webp" alt="">
|
||||
<img class="bg4" style="right: {(current - 0) * 100}%;" src="/screenshots/mangadex.png" alt="">
|
||||
</div>
|
||||
<div class="blur z-1"></div>
|
||||
<div class="bg z-2">
|
||||
<img class="bg1" style="right: {(current - 3) * 100}%;" src="/screenshots/heaventaker/heaventaker.webp" alt="">
|
||||
<img class="bg2" style="right: {(current - 2) * 100}%;" src="/screenshots/animasher.webp" alt="">
|
||||
<img class="bg3" style="right: {(current - 1) * 100}%;" src="/screenshots/ignibg.webp" alt="">
|
||||
<img class="bg4" style="right: {(current - 0) * 100}%;" src="/screenshots/mangadex.png" alt="">
|
||||
</div>
|
||||
{#each [0, 1, 2] as i}
|
||||
<div class="{i !== 1 ? "bg" : "blur"} z-{i}">
|
||||
{#if i !== 1}
|
||||
<img class="bg1" style="right: {(current - 3) * 100}%;" src="/screenshots/heaventaker/heaventaker.webp" alt="">
|
||||
<img class="bg2" style="right: {(current - 2) * 100}%;" src="/screenshots/animasher.webp" alt="">
|
||||
<img class="bg3" style="right: {(current - 1) * 100}%;" src="/screenshots/tictactoe.png" alt="">
|
||||
<img class="bg4" style="right: {(current - 0) * 100}%;" src="/screenshots/mangadex.png" alt="">
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
|
|
@ -42,7 +39,6 @@
|
|||
padding: 40px 120px;
|
||||
padding: 40px min(120px, 10vw);
|
||||
margin: 2rem auto;
|
||||
/* min-height: calc(100vh - 129px - 80px + 5px); */
|
||||
max-height: 1080px;
|
||||
max-width: 1500px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
<script>
|
||||
import { DateTime } from "luxon";
|
||||
import { scale } from "svelte/transition";
|
||||
|
||||
// this component used to support authors and categories, removed because I didn't use them.
|
||||
|
||||
export var bigThumbnail;
|
||||
// export var categories = [];
|
||||
// export var author;
|
||||
export var date;
|
||||
export var title;
|
||||
// export var authorIcon;
|
||||
export var description;
|
||||
export var path;
|
||||
|
||||
|
|
@ -20,18 +18,9 @@
|
|||
<img src={bigThumbnail} styles="width: 800px; height: 400px;" alt="Thumbnail" class="thumbnail" draggable={false}>
|
||||
{/if}
|
||||
<div class="data">
|
||||
<!-- <div class="categories">
|
||||
{#each categories as category}
|
||||
<span>{category}</span>
|
||||
{/each}
|
||||
</div> -->
|
||||
<h3>{title}</h3>
|
||||
<p>{description}</p>
|
||||
<div class="author">
|
||||
<!-- <img src={authorIcon} alt="Avatar of author" draggable={false}>
|
||||
<span class="spacer">—</span>
|
||||
<span class="author">{author}</span>
|
||||
<span class="spacer">—</span> -->
|
||||
<span class="date">{dt.toRelativeCalendar()} ({dt.toLocaleString(DateTime.DATE_FULL)})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { goatCounter } from "$lib/goatcounter";
|
||||
import { goto } from "$app/navigation";
|
||||
export var image; // "https://picsum.photos/725/350?random=" + Math.floor(Math.random() * 5000);
|
||||
export var image;
|
||||
export var link = "";
|
||||
export var grayscale = false;
|
||||
export var extradark = false;
|
||||
133
src/lib/components/home/projects.svelte
Normal file
133
src/lib/components/home/projects.svelte
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<script>
|
||||
import Project from "./project.svelte";
|
||||
|
||||
/** @type {null | "websites" | "applications" | "bots"} */
|
||||
export var appTypeHover;
|
||||
</script>
|
||||
|
||||
<div class="projects" id="projects">
|
||||
<div>
|
||||
<h2>
|
||||
I helped many projects come to life. Here are some examples:
|
||||
</h2>
|
||||
<Project
|
||||
link="/projects/heaventaker"
|
||||
image="/screenshots/heaventaker/heaventaker.webp"
|
||||
grayscale={appTypeHover && appTypeHover === "bots"}
|
||||
width={2050}
|
||||
height={1080}
|
||||
name="Heaventaker"
|
||||
clickable
|
||||
target="_self"
|
||||
>
|
||||
<b>Heaventaker</b> - Helltaker fan game
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
<img src="/azrael.gif" alt="" style="height: 24px; width: 24px; display: inline"> Heaventaker is a helltaker fan-game visual novel and puzzle game.
|
||||
</p>
|
||||
<p>
|
||||
Heaventaker currently has 3 different puzzles and 4 angels to collect. Playable online on the website, or on Android devices (application installable from Google Play Store)
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
<Project
|
||||
image="/screenshots/animasher.webp"
|
||||
grayscale={appTypeHover && appTypeHover !== "websites"}
|
||||
extradark
|
||||
width={1920}
|
||||
height={940}
|
||||
link="https://animasher.net"
|
||||
name="Animasher"
|
||||
>
|
||||
<b>Animasher</b> - Platform for creating and sharing animations
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
Animasher is a work in progress platform for creating and sharing animations online.
|
||||
</p>
|
||||
<p>
|
||||
It allows people to easily create animations inside the website, and then share it with the world, as well as communicate with other creators to improve themselves.
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
</div>
|
||||
<div>
|
||||
<div class="pad"></div>
|
||||
<Project
|
||||
link="https://manga.danbulant.eu"
|
||||
image="/screenshots/mangadex.png"
|
||||
grayscale={appTypeHover && appTypeHover !== "websites"}
|
||||
width={803}
|
||||
height={382}
|
||||
name="Mangades reader"
|
||||
>
|
||||
<b>Mangades</b> - Mangadex viewer
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
A Mangadex client, with EPUB/CBZ download options, and a sleek UI.
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
<Project
|
||||
link="https://tictactoe.danbulant.eu"
|
||||
image="/screenshots/tictactoe.png"
|
||||
grayscale={appTypeHover && appTypeHover !== "websites"}
|
||||
width={1105}
|
||||
height={720}
|
||||
name="TicTacToe"
|
||||
>
|
||||
<b>Ultimate tictactoe</b> - Online Tic-Tac-Toe, with a twist
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
Online Tic-Tac-Toe game that can be played with a friend locally or online.
|
||||
Play across 3x3 boards, each with a "classic" 3x3 grid inside.
|
||||
When you play your move, the next player has to play in the board that corresponds to the cell you played in.
|
||||
The corresponding grid is highlighted when you hover over a cell.
|
||||
Please note that the rules are slightly different that what's normally known as utlimate tictactoe.
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.projects {
|
||||
max-width: 1380px;
|
||||
}
|
||||
.projects {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 0 20px 0px 20px;
|
||||
}
|
||||
@media (min-width: 1520px) {
|
||||
.projects {
|
||||
margin: 0 auto 0px auto;
|
||||
}
|
||||
}
|
||||
.projects > div {
|
||||
width: calc(50% - 40px);
|
||||
}
|
||||
.projects .pad {
|
||||
margin-top: 110px;
|
||||
}
|
||||
@media (max-width: 860px) {
|
||||
.projects > div {
|
||||
width: calc(100% - 80px);
|
||||
margin: auto;
|
||||
}
|
||||
.projects .pad {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.projects h2 {
|
||||
margin: 1em 0 1em 10px;
|
||||
}
|
||||
}
|
||||
.projects h2 {
|
||||
font-size: 29px;
|
||||
font-weight: 400;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 40px;
|
||||
margin-inline-end: 40px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
import { scale } from "svelte/transition";
|
||||
|
||||
export var selected = true;
|
||||
|
||||
|
|
@ -13,7 +13,8 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="dialog" class:dark={$darkmode} class:selected on:mousedown={() => shouldClose = true} on:mousemove={() => shouldClose = false} on:mouseup={close}>
|
||||
{#if selected}
|
||||
<div class="dialog" transition:scale={{ duration: 300, start: 0.8, opacity: 0 }} on:mousedown={() => shouldClose = true} on:mousemove={() => shouldClose = false} on:mouseup={close}>
|
||||
<div class="main">
|
||||
{#if selected === "typescript"}
|
||||
<h2>Typescript</h2>
|
||||
|
|
@ -41,14 +42,14 @@
|
|||
<p>I'm learning C# at my school, in addition to learning Unity and looking into the osu!framework.</p>
|
||||
<p>Currently, I don't have any project worth sharing.</p>
|
||||
{:else if selected === "git"}
|
||||
<h2>Git + GitHub</h2>
|
||||
<h2>Git & GitHub</h2>
|
||||
<p>I use Git version control system for all of my projects, even if I don't upload them to GitHub. Most of my projects can be found on GitHub.</p>
|
||||
<!-- svelte-ignore security-anchor-rel-noreferrer -->
|
||||
<p>My GitHub profile is @<a href="https://github.com/danbulant" target="_blank" rel="noopener">danbulant</a>.</p>
|
||||
<!-- svelte-ignore security-anchor-rel-noreferrer -->
|
||||
<p>The source code of this website is available <a href="https://github.com/danbulant/design" target="_blank" rel="noopener">here</a></p>
|
||||
{:else if selected === "docker"}
|
||||
<h2>Docker + Docker compose + Docker desktop</h2>
|
||||
<h2>Docker, Docker compose & Docker desktop</h2>
|
||||
<p><a href="https://www.docker.com" rel="noopener noreferrer" target="_blank">Docker</a> is the most widely used container runtime. <a href="https://docs.docker.com/compose/" target="_blank" rel="noopener noreferrer">Docker compose</a> makes it easy to orchestrate multiple containers, and finally, <a href="https://docs.docker.com/desktop/" target="_blank" rel="noopener noreferrer">Docker desktop</a> is the easiest way to get Docker on Windows.</p>
|
||||
<p>Most of my projects that I run on a server run in Docker, to make it easy to replicate environment, as well as make deployments easier via Nomad.</p>
|
||||
{:else if selected === "react"}
|
||||
|
|
@ -102,7 +103,7 @@
|
|||
<p>Node.js is a javascript runtime for servers and desktop applications (via <span class="a" on:click={() => selected="electron"} on:keydown={() => selected="electron"}>Electron</span>).</p>
|
||||
<p>I use Node.js in nearly all of my projects. In case of websites, as a build platform, and in case of backend servers or desktop applications, as the primary runtime.</p>
|
||||
<!-- svelte-ignore security-anchor-rel-noreferrer -->
|
||||
<p>I used Node.js from simply rollup scripts (used in <a href="http://github.com/danbulant/design" target="_blank" rel="noopener">this website</a>), to backend servers and APIs (in case of Animasher and igni website), to <a href="https://github.com/danbulant/test-x" target="_blank" rel="noopener">Linux Window Manager</a> and <a href="https://github.com/danbulant/ssps-bot" target="_blank" rel="noopener">Discord Bots</a>.</p>
|
||||
<p>I used Node.js from backend servers and APIs (in case of Animasher and igni website), to <a href="https://github.com/danbulant/test-x" target="_blank" rel="noopener">Linux Window Manager</a> and <a href="https://github.com/danbulant/ssps-bot" target="_blank" rel="noopener">Discord Bots</a>.</p>
|
||||
{:else if selected === "deno"}
|
||||
<h2>Deno</h2>
|
||||
<p>Deno is an alternative to <span class="a" on:click={() => selected="node"} on:keydown={() => selected="node"}>Node.js</span> by the same authors, written in <span class="a" on:click={() => selected="rust"} on:keydown={() => selected="rust"}>Rust</span>.</p>
|
||||
|
|
@ -131,16 +132,13 @@
|
|||
Click to close.
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.dialog {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: opacity .3s, transform .3s;
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
pointer-events: none;
|
||||
backdrop-filter: blur(25px);
|
||||
-webkit-backdrop-filter: blur(25px);
|
||||
padding: 8px 16px;
|
||||
|
|
@ -156,17 +154,8 @@
|
|||
background: rgba(255,255,255,0.1);
|
||||
box-shadow: 0.6px 1.3px 1.3px hsl(0deg 0% 0% / 0.48);
|
||||
}
|
||||
/* @supports (-moz-appearance:none) {
|
||||
.dialog {
|
||||
background: rgba(255,255,255,0.9) !important;
|
||||
}
|
||||
.dark.dialog {
|
||||
background: rgba(70,70,70,0.97) !important;
|
||||
}
|
||||
} */
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
margin-block-start: 0;
|
||||
@apply m-0 text-2xl mb-2;
|
||||
}
|
||||
.main {
|
||||
flex-grow: 1;
|
||||
|
|
@ -183,12 +172,7 @@
|
|||
.a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.dark.dialog {
|
||||
background: rgba(255,255,255,0.2);
|
||||
}
|
||||
.dialog.selected {
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
:global(.dark) .dialog {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
||||
179
src/lib/components/home/technologyList.svelte
Normal file
179
src/lib/components/home/technologyList.svelte
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
<script>
|
||||
import TechnologyDetails from "./technologyDetails.svelte";
|
||||
|
||||
var technologySelected = null;
|
||||
var technologyListHovered = false;
|
||||
</script>
|
||||
|
||||
<div class="also relative">
|
||||
<TechnologyDetails bind:selected={technologySelected} />
|
||||
<h2 class="text-center font-semibold text-2xl m-0">I also worked with the following:</h2>
|
||||
<noscript class="text-center text-white">Clicking won't work if javascript is not enabled.</noscript>
|
||||
<span class="text-center" class:text-gray={!technologyListHovered} class:text-white={technologyListHovered}>{typeof window !== "undefined" && window.matchMedia("(hover: none) and (pointer: coarse)").matches ? "Touch" : "Click"} each technology for more details about why I'm using it.</span>
|
||||
<div class="split" class:text-gray={technologyListHovered} on:mouseenter={() => technologyListHovered = true} on:mouseleave={() => technologyListHovered = false}>
|
||||
<ul>
|
||||
<li on:click={() => technologySelected = "typescript"} on:keydown={() => technologySelected = "typescript"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/typescript/typescript-original.svg" alt="" draggable={false} />
|
||||
Typescript
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "rust"} on:keydown={() => technologySelected = "rust"}>
|
||||
<img class="white" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/rust/rust-plain.svg" alt="" draggable={false} />
|
||||
Rust
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "x11"} on:keydown={() => technologySelected = "x11"}>
|
||||
<img src="/tech/x11.png" alt="" draggable={false} />
|
||||
X11
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "cs"} on:keydown={() => technologySelected = "cs"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/csharp/csharp-plain.svg" alt="" draggable={false} />
|
||||
C#
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "git"} on:keydown={() => technologySelected = "git"}>
|
||||
<img class="white" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg" alt="" draggable={false} />
|
||||
Git + GitHub
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "docker"} on:keydown={() => technologySelected = "docker"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/docker/docker-plain.svg" alt="" draggable={false} />
|
||||
Docker + Docker compose
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "react"} on:keydown={() => technologySelected = "react"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/react/react-original.svg" alt="" draggable={false} />
|
||||
React
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "nomad"} on:keydown={() => technologySelected = "nomad"}>
|
||||
<img src="/tech/nomad.svg" alt="" draggable={false} />
|
||||
Nomad
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "consul"} on:keydown={() => technologySelected = "consul"}>
|
||||
<img src="/tech/consul.svg" alt="" draggable={false} />
|
||||
Consul
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "discord"} on:keydown={() => technologySelected = "discord"}>
|
||||
<img src="/tech/discord.png" alt="" draggable={false}>
|
||||
Discord bots
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li on:click={() => technologySelected = "electron"} on:keydown={() => technologySelected = "electron"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/electron/electron-original.svg" alt="" draggable={false} />
|
||||
Electron
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "svelte"} on:keydown={() => technologySelected = "svelte"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/svelte/svelte-original.svg" alt="" draggable={false} />
|
||||
Svelte + SvelteKit
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "mysql"} on:keydown={() => technologySelected = "mysql"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/mysql/mysql-original.svg" alt="" draggable={false} />
|
||||
MySQL/MariaDB
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "mongodb"} on:keydown={() => technologySelected = "mongodb"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/mongodb/mongodb-plain.svg" alt="" draggable={false} />
|
||||
MongoDB
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "postgresql"} on:keydown={() => technologySelected = "postgresql"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/postgresql/postgresql-plain.svg" alt="" draggable={false} />
|
||||
PostgreSQL
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "node"} on:keydown={() => technologySelected = "node"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/nodejs/nodejs-original.svg" alt="" draggable={false} />
|
||||
Node.js
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "deno"} on:keydown={() => technologySelected = "deno"}>
|
||||
<img class="white" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/denojs/denojs-original.svg" alt="" draggable={false} />
|
||||
Deno
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "linux"} on:keydown={() => technologySelected = "linux"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/linux/linux-original.svg" alt="" draggable={false} />
|
||||
Linux
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "nginx"} on:keydown={() => technologySelected = "nginx"}>
|
||||
<img src="/tech/nginx.svg" alt="" draggable={false} />
|
||||
Nginx
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "cloudflare"} on:keydown={() => technologySelected = "cloudflare"}>
|
||||
<img src="/tech/cloudflare.png" alt="" draggable={false} />
|
||||
Cloudflare
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.also > span {
|
||||
transition: color .3s;
|
||||
}
|
||||
.text-gray {
|
||||
color: rgb(150, 150, 150);
|
||||
}
|
||||
.text-gray img {
|
||||
filter: grayscale(70%);
|
||||
transition: filter .3s;
|
||||
}
|
||||
.text-white {
|
||||
color: black;
|
||||
}
|
||||
:global(.dark) .text-white {
|
||||
color: white;
|
||||
}
|
||||
.also {
|
||||
margin: 50px auto 0 auto;
|
||||
max-width: 850px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.also > span {
|
||||
margin-bottom: 25px;
|
||||
display: block;
|
||||
}
|
||||
.split {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.split ul {
|
||||
min-width: 340px;
|
||||
margin: 0 auto;
|
||||
padding-left: 20px;
|
||||
list-style-type: none;
|
||||
}
|
||||
.also li {
|
||||
height: 32px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
cursor: pointer;
|
||||
transition: transform .3s, color .2s;
|
||||
}
|
||||
.also li:hover {
|
||||
color: black;
|
||||
}
|
||||
.also li:hover img {
|
||||
filter: grayscale(0%);
|
||||
}
|
||||
.dark .also li:hover {
|
||||
color: white;
|
||||
}
|
||||
.also li:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.also li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
left: -20px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 6px;
|
||||
background-color: black;
|
||||
transition: background-color .3s;
|
||||
}
|
||||
.dark .also li::before {
|
||||
background-color: white;
|
||||
}
|
||||
.also li img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
import { onMount } from "svelte";
|
||||
import Button from "./button.svelte";
|
||||
import Split from "./split.svelte";
|
||||
import { browser } from "$app/environment";
|
||||
|
||||
function toggle() {
|
||||
$darkmode = !$darkmode;
|
||||
|
|
@ -16,15 +17,17 @@
|
|||
};
|
||||
document.addEventListener("scroll", handleScroll);
|
||||
|
||||
handleScroll();
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
});
|
||||
|
||||
$: progress = typeof window === "undefined" ? 1 : Math.min(1, scrollTop / 40);
|
||||
$: progress = !browser ? 1 : Math.min(1, scrollTop / 40);
|
||||
</script>
|
||||
|
||||
<nav class="bar fixed top-0 left-0 z-99 w-100vw mx-auto mb-30px" class:dark={$darkmode}
|
||||
<nav class="bar fixed top-0 left-0 z-99 w-100vw mx-auto mb-30px"
|
||||
style:background="rgba({$darkmode ? "28,28,33" : "255,255,255"}, {progress * 0.2})"
|
||||
style:backdrop-filter="blur({progress*20}px)">
|
||||
<div class="subbar w-full flex items-center justify-between max-w-8xl m-auto">
|
||||
|
|
@ -51,7 +54,7 @@
|
|||
@apply w-full flex flex-between items-center p-2;
|
||||
background: rgba(255,255,255, 0.2);
|
||||
}
|
||||
.dark.bar {
|
||||
:global(.dark) .bar {
|
||||
background: rgba(28, 28, 33, 0.8);
|
||||
}
|
||||
.bar .subbar > * {
|
||||
|
|
@ -68,13 +71,13 @@
|
|||
color: black;
|
||||
margin: 0;
|
||||
}
|
||||
.dark.bar h3 {
|
||||
:global(.dark) .bar h3 {
|
||||
color: white;
|
||||
}
|
||||
.bar a {
|
||||
color: #202020b2;
|
||||
}
|
||||
.dark.bar a {
|
||||
:global(.dark) .bar a {
|
||||
color: rgba(191, 191, 191, 0.698);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
<script>
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
import { DateTime } from "luxon";
|
||||
|
||||
// this component used to support authors and categories, removed because I didn't use them.
|
||||
export var thumbnail;
|
||||
// export var categories = [];
|
||||
// export var author;
|
||||
export var date;
|
||||
export var title;
|
||||
// export var authorIcon;
|
||||
export var currentHover;
|
||||
export var path;
|
||||
export var description
|
||||
|
|
@ -26,25 +23,16 @@
|
|||
$: dt = DateTime.fromISO(date);
|
||||
</script>
|
||||
|
||||
<a href={path} class:dark={$darkmode} class="post transition duration-300 block transform active:scale-95" class:grayscale on:mouseenter={mouseenter} on:mouseleave={mouseleave}>
|
||||
<a href={path} class="post transition duration-300 block transform active:scale-95" class:grayscale on:mouseenter={mouseenter} on:mouseleave={mouseleave}>
|
||||
{#if thumbnail}
|
||||
<img src={thumbnail} alt="Thumbnail" class="thumbnail" draggable={false}>
|
||||
{:else}
|
||||
<div class="thumbnail"></div>
|
||||
{/if}
|
||||
<div class="data">
|
||||
<!-- <div class="categories">
|
||||
{#each categories as category}
|
||||
<span>{category}</span>
|
||||
{/each}
|
||||
</div> -->
|
||||
<h4>{title}</h4>
|
||||
<p>{description}</p>
|
||||
<div class="author">
|
||||
<!-- <img src={authorIcon} alt="Avatar of author" draggable={false}>
|
||||
<span class="spacer">—</span>
|
||||
<span class="author">{author}</span>
|
||||
<span class="spacer">—</span> -->
|
||||
<span class="date">{dt.toRelativeCalendar()} ({dt.toLocaleString(DateTime.DATE_FULL)})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -79,9 +67,6 @@
|
|||
font-weight: 400;
|
||||
font-size: 22px;
|
||||
}
|
||||
/* .categories {
|
||||
color: #0054E2;
|
||||
} */
|
||||
.thumbnail {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
|
|
@ -91,16 +76,12 @@
|
|||
box-shadow: 0 0 5px rgb(145, 145, 145);
|
||||
border-radius: 5px;
|
||||
}
|
||||
.dark .thumbnail {
|
||||
:global(.dark) .thumbnail {
|
||||
box-shadow: 0 0 5px rgb(0, 0, 0);
|
||||
}
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
/* .author img {
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
} */
|
||||
.author {
|
||||
color: gray;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.main {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
let newtitle = "";
|
||||
let options = new Map;
|
||||
|
||||
// Faviconkit, a free service that provides favicons for any domain
|
||||
$: defaultfavicon = `https://filthy-cyan-otter.faviconkit.com/${domain}/32`;
|
||||
let favicon = defaultfavicon;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,12 @@
|
|||
<!-- A simple callout with header and slot body. Header background colored according to color, and the whole callout has a left border colored as well. -->
|
||||
<div class:minimal class:closed class:closable class="w-full rounded border-l border-l-4 my-6 color-shadow" style:border-left-color={color} style:--shadow-color="{color}0D">
|
||||
<div on:click={toggle} on:keydown={toggle} class="header rounded-tr-lg" style:background-color="{color}40" class:dark-bg={isDark}>
|
||||
<h1 class="text-big p-0 m-0">
|
||||
<h1>
|
||||
<slot name="title"/>
|
||||
</h1>
|
||||
{#if closable}
|
||||
<span class="toggle">{closed ? "Click to view more" : "Click to dismiss"}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="content rounded-br-lg p-4 backdrop-blur -mt-1 pt-5">
|
||||
<slot />
|
||||
|
|
@ -49,9 +52,18 @@
|
|||
@apply p-0.5 pl-4;
|
||||
}
|
||||
.header {
|
||||
@apply text-black p-4;
|
||||
@apply text-black p-4 flex;
|
||||
}
|
||||
h1 {
|
||||
@apply text-big p-0 m-0 flex-grow;
|
||||
}
|
||||
.header.dark-bg {
|
||||
@apply text-white;
|
||||
}
|
||||
.header .toggle {
|
||||
@apply text-black/50;
|
||||
}
|
||||
.header.dark-bg .toggle {
|
||||
@apply text-white/50;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
</script>
|
||||
<!-- Used for custom code highlight -->
|
||||
|
||||
{#if $$props["data-mdx-pretty-code"]}
|
||||
<code data-theme={$$props["data-theme"]} style:color={$$props["data-color"]}><slot /></code>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
</Callout>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.inner {
|
||||
@apply p-2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
</script>
|
||||
<!-- Used for inline code highlight -->
|
||||
|
||||
{#if $$props["data-mdx-pretty-code"]}
|
||||
<code data-theme={$$props["data-theme"]} style:color={$$props["data-color"]}><slot /></code>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
<script>
|
||||
/**
|
||||
* Taken from the Heaventaker project.
|
||||
* Licensed under GPLv3 (same license as this project).
|
||||
*/
|
||||
|
||||
export var href;
|
||||
</script>
|
||||
|
||||
|
|
@ -59,7 +64,4 @@
|
|||
margin-bottom: 15px;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
.button.button:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
<script>
|
||||
// not used anywhere as of now.
|
||||
// planned showcase of some other projects (possibly WASM compiled rust shell, or just for fun)
|
||||
import { Terminal } from 'xterm';
|
||||
import "xterm/css/xterm.css";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script context="module">
|
||||
// module context is used for when something else imports this file.
|
||||
// Here, it's used to have custom components for certain elements in blog posts.
|
||||
import span from "../components/posts/span.svelte";
|
||||
import code from "../components/posts/code.svelte";
|
||||
import a from "../components/posts/a.svelte";
|
||||
|
|
@ -43,7 +45,7 @@
|
|||
{/if}
|
||||
</svelte:head>
|
||||
|
||||
<main class:dark={$darkmode} class="post-layout">
|
||||
<main class="post-layout">
|
||||
<span><a href="/posts">Posts</a> /</span>
|
||||
<h1>{title}</h1>
|
||||
<div class="flex justify-between flex-wrap">
|
||||
|
|
@ -51,7 +53,7 @@
|
|||
<span>{categories.join(", ")}</span>
|
||||
</div>
|
||||
<slot />
|
||||
<noscript>Although the page mostly works without Javascript, you won't be able to comment. Also, I acknowledge the privacy flaws, but Javascript is a fundamental part of modern web, and shouldn't be disabled. Maybe use an adblock instead of disabling it for everything?</noscript>
|
||||
<noscript><hr>Although the page mostly works without Javascript, you won't be able to comment. Also, I acknowledge the privacy flaws, but Javascript is a fundamental part of modern web, and shouldn't be disabled. Maybe use an adblock instead of disabling it for everything?</noscript>
|
||||
<script src="https://utteranc.es/client.js"
|
||||
repo="danbulant/design"
|
||||
issue-term="pathname"
|
||||
|
|
@ -62,13 +64,13 @@
|
|||
</script>
|
||||
</main>
|
||||
|
||||
<hr class:dark={$darkmode}>
|
||||
<hr>
|
||||
|
||||
<footer>
|
||||
Daniel Bulant - Blog posts CC-BY-SA (unless otherwise specified)
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
:global(body .post-layout a) {
|
||||
color: rgb(4, 192, 192);
|
||||
}
|
||||
|
|
@ -179,7 +181,7 @@
|
|||
text-align: center;
|
||||
padding: 20px 0 40px;
|
||||
}
|
||||
hr.dark {
|
||||
:global(.dark) hr {
|
||||
border-color: #999;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
import { writable } from "svelte/store";
|
||||
|
||||
// no idea how to make this better.
|
||||
// it works! But isn't very performant - darkmode is switched after loading the page, not very friendly
|
||||
// could probably set a cookie and have the class be set in SSR as well, I don't really want to spend the time on that now.
|
||||
// TODO: make this use cookies and SSR
|
||||
const darkmode = writable(
|
||||
typeof window === "undefined" ? false :
|
||||
(JSON.parse(localStorage.getItem("darkmode")) || window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
import PageTransition from "$lib/components/pageTransition.svelte";
|
||||
import "virtual:windi.css";
|
||||
import { browser, dev } from "$app/environment";
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { apm } from "$lib/apm";
|
||||
import { navigating, page } from "$app/stores";
|
||||
import Spinner from "$lib/components/icons/spinner.svelte";
|
||||
|
|
@ -21,7 +20,7 @@
|
|||
<Navbar />
|
||||
|
||||
{#if $navigating}
|
||||
<div transition:fly={{ duration: 200, opacity: 0, y: -20 }} class="fixed bg-hex-1f1f1f top-20 left-1/2 transform -translate-x-1/2 rounded-full w-14 h-14 p-2 z-99">
|
||||
<div transition:fly={{ duration: 200, opacity: 0, y: -20 }} class="spinner-container">
|
||||
<Spinner />
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -32,8 +31,11 @@
|
|||
</PageTransition>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
:global(*) {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.spinner-container {
|
||||
@apply fixed bg-hex-1f1f1f top-20 left-1/2 transform -translate-x-1/2 rounded-full w-14 h-14 p-2 z-99;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,12 +4,9 @@
|
|||
import Contact from "$lib/components/contact.svelte";
|
||||
import Hero from "$lib/components/hero.svelte";
|
||||
import Posts from "$lib/components/posts.svelte";
|
||||
import Project from "$lib/components/project.svelte";
|
||||
import TechnologyDetails from "$lib/components/technologyDetails.svelte";
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
import TechnologyList from "$lib/components/home/technologyList.svelte";
|
||||
import Projects from "$lib/components/home/projects.svelte";
|
||||
|
||||
var technologySelected = null;
|
||||
var technologyHover = false;
|
||||
/** @type {null | "websites" | "applications" | "bots"} */
|
||||
var appTypeHover = null;
|
||||
|
||||
|
|
@ -21,7 +18,7 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Daniel Bulant - Homepage</title>
|
||||
<title>Daniel Bulant</title>
|
||||
<link href="/posts/rss.xml" type="application/rss+xml" rel="alternate" title="Blog posts - RSS" />
|
||||
<meta property="og:title" content="Daniel Bulant - Homepage"/>
|
||||
<meta name="description" content="Homepage of danbulant.eu - List of my projects, contact info.">
|
||||
|
|
@ -35,11 +32,11 @@
|
|||
<meta property="og:profile:gender" content="male" />
|
||||
</svelte:head>
|
||||
|
||||
<main class:dark={$darkmode}>
|
||||
<main>
|
||||
<Hero {appTypeHover}>
|
||||
<h1 class="font-bold">I'm making <b on:mouseenter={() => appTypeHover = "websites"} on:mouseleave={() => appTypeHover == "websites" && (appTypeHover = null)}>websites</b>,
|
||||
<b on:mouseenter={() => appTypeHover = "applications"} on:mouseleave={() => appTypeHover == "applications" && (appTypeHover = null)}>mobile applications</b> and
|
||||
<b on:mouseenter={() => appTypeHover = "bots"} on:mouseleave={() => appTypeHover == "bots" && (appTypeHover = null)}>discord bots</b>.</h1>
|
||||
<h1 class="font-bold">I'm making <b on:mouseenter={() => appTypeHover = "websites"} on:mouseleave={() => appTypeHover === "websites" && (appTypeHover = null)}>websites</b>,
|
||||
<b on:mouseenter={() => appTypeHover = "applications"} on:mouseleave={() => appTypeHover === "applications" && (appTypeHover = null)}>mobile applications</b> and
|
||||
<b on:mouseenter={() => appTypeHover = "websites"} on:mouseleave={() => appTypeHover === "website" && (appTypeHover = null)}>online games</b>.</h1>
|
||||
<!-- <h3>To be used later</h3> -->
|
||||
<div class="flex gap-4">
|
||||
<Button blur class="!p-4" href="#projects">Check out my work</Button>
|
||||
|
|
@ -57,186 +54,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</Hero>
|
||||
<div class="projects" id="projects">
|
||||
<div>
|
||||
<h2>
|
||||
I helped many projects come to life. Here are some examples:
|
||||
</h2>
|
||||
<Project
|
||||
link="/projects/heaventaker"
|
||||
image="/screenshots/heaventaker/heaventaker.webp"
|
||||
grayscale={appTypeHover && appTypeHover === "bots"}
|
||||
width={2050}
|
||||
height={1080}
|
||||
name="Heaventaker"
|
||||
clickable
|
||||
target="_self"
|
||||
>
|
||||
<b>Heaventaker</b> - Helltaker fan game
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
<img src="/azrael.gif" alt="" style="height: 24px; width: 24px; display: inline"> Heaventaker is a helltaker fan-game visual novel and puzzle game.
|
||||
</p>
|
||||
<p>
|
||||
Heaventaker currently has 3 different puzzles and 4 angels to collect. Playable online on the website, or on Android devices (application installable from Google Play Store)
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
<Project
|
||||
image="/screenshots/animasher.webp"
|
||||
grayscale={appTypeHover && appTypeHover !== "websites"}
|
||||
extradark
|
||||
width={1920}
|
||||
height={940}
|
||||
link="https://animasher.net"
|
||||
name="Animasher"
|
||||
>
|
||||
<b>Animasher</b> - Platform for creating and sharing animations
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
Animasher is a work in progress platform for creating and sharing animations online.
|
||||
</p>
|
||||
<p>
|
||||
It allows people to easily create animations inside the website, and then share it with the world, as well as communicate with other creators to improve themselves.
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
</div>
|
||||
<div>
|
||||
<div class="pad"></div>
|
||||
<Project
|
||||
link="https://manga.danbulant.eu"
|
||||
image="/screenshots/mangadex.png"
|
||||
grayscale={appTypeHover && appTypeHover !== "websites"}
|
||||
width={803}
|
||||
height={382}
|
||||
name="Mangades reader"
|
||||
>
|
||||
<b>Mangades</b> - Mangadex downloader and viewer
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
Mangades is a manga downloader from Mangadex.
|
||||
</p>
|
||||
<p>
|
||||
It can download mangas to EPUB or CBZ files online from browsers
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
<Project
|
||||
link="https://top.gg/bot/739864286775738399"
|
||||
image="/screenshots/ignibg.webp"
|
||||
grayscale={appTypeHover && appTypeHover === "applications"}
|
||||
width={1080}
|
||||
height={720}
|
||||
name="igni discord bot"
|
||||
>
|
||||
<b>igni</b> - The universal Discord bot
|
||||
<svelte:fragment slot="desc">
|
||||
<p>
|
||||
igni is a universal Discord bot, making managing Discord communities easy.
|
||||
</p>
|
||||
<p>
|
||||
It includes customizability, music playback (Youtube, SoundCloud, Spotify), moderation commands, anime, automation, games and more.
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
</Project>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
In addition, this website is open-source and available on <img class="white inline" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg" style="height: 1em; width: 1em;" alt=""> <a href="https://github.com/danbulant/design" style="color: rgb(255, 102, 128)">GitHub</a>
|
||||
</div>
|
||||
<div class="also relative">
|
||||
<TechnologyDetails bind:selected={technologySelected} />
|
||||
<h2 class="text-center font-semibold text-2xl">I also worked with the following:</h2>
|
||||
<noscript class="text-center text-white">Clicking won't work if javascript is not enabled.</noscript>
|
||||
<span class="text-center" class:text-gray={!technologyHover} class:text-white={technologyHover}>{typeof window !== "undefined" && window.matchMedia("(hover: none) and (pointer: coarse)").matches ? "Touch" : "Click"} each technology for more details about why I'm using it.</span>
|
||||
<div class="split" class:text-gray={technologyHover} on:mouseenter={() => technologyHover = true} on:mouseleave={() => technologyHover = false}>
|
||||
<ul>
|
||||
<li on:click={() => technologySelected = "typescript"} on:keydown={() => technologySelected = "typescript"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/typescript/typescript-original.svg" alt="" draggable={false} />
|
||||
Typescript
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "rust"} on:keydown={() => technologySelected = "rust"}>
|
||||
<img class="white" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/rust/rust-plain.svg" alt="" draggable={false} />
|
||||
Rust
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "x11"} on:keydown={() => technologySelected = "x11"}>
|
||||
<img src="/tech/x11.png" alt="" draggable={false} />
|
||||
X11
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "cs"} on:keydown={() => technologySelected = "cs"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/csharp/csharp-plain.svg" alt="" draggable={false} />
|
||||
C#
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "git"} on:keydown={() => technologySelected = "git"}>
|
||||
<img class="white" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg" alt="" draggable={false} />
|
||||
Git + GitHub
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "docker"} on:keydown={() => technologySelected = "docker"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/docker/docker-plain.svg" alt="" draggable={false} />
|
||||
Docker + Docker compose
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "react"} on:keydown={() => technologySelected = "react"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/react/react-original.svg" alt="" draggable={false} />
|
||||
React
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "nomad"} on:keydown={() => technologySelected = "nomad"}>
|
||||
<img src="/tech/nomad.svg" alt="" draggable={false} />
|
||||
Nomad
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "consul"} on:keydown={() => technologySelected = "consul"}>
|
||||
<img src="/tech/consul.svg" alt="" draggable={false} />
|
||||
Consul
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "discord"} on:keydown={() => technologySelected = "discord"}>
|
||||
<img src="/tech/discord.png" alt="" draggable={false}>
|
||||
Discord bots
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li on:click={() => technologySelected = "electron"} on:keydown={() => technologySelected = "electron"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/electron/electron-original.svg" alt="" draggable={false} />
|
||||
Electron
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "svelte"} on:keydown={() => technologySelected = "svelte"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/svelte/svelte-original.svg" alt="" draggable={false} />
|
||||
Svelte + SvelteKit
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "mysql"} on:keydown={() => technologySelected = "mysql"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/mysql/mysql-original.svg" alt="" draggable={false} />
|
||||
MySQL/MariaDB
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "mongodb"} on:keydown={() => technologySelected = "mongodb"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/mongodb/mongodb-plain.svg" alt="" draggable={false} />
|
||||
MongoDB
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "postgresql"} on:keydown={() => technologySelected = "postgresql"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/postgresql/postgresql-plain.svg" alt="" draggable={false} />
|
||||
PostgreSQL
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "node"} on:keydown={() => technologySelected = "node"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/nodejs/nodejs-original.svg" alt="" draggable={false} />
|
||||
Node.js
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "deno"} on:keydown={() => technologySelected = "deno"}>
|
||||
<img class="white" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/denojs/denojs-original.svg" alt="" draggable={false} />
|
||||
Deno
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "linux"} on:keydown={() => technologySelected = "linux"}>
|
||||
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/linux/linux-original.svg" alt="" draggable={false} />
|
||||
Linux
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "nginx"} on:keydown={() => technologySelected = "nginx"}>
|
||||
<img src="/tech/nginx.svg" alt="" draggable={false} />
|
||||
Nginx
|
||||
</li>
|
||||
<li on:click={() => technologySelected = "cloudflare"} on:keydown={() => technologySelected = "cloudflare"}>
|
||||
<img src="/tech/cloudflare.png" alt="" draggable={false} />
|
||||
Cloudflare
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Projects {appTypeHover} />
|
||||
<div class="text-center">
|
||||
In addition, this website is open-source and available on <img class="white inline w-1em h-1em" src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg" alt=""> <a href="https://github.com/danbulant/design" style="color: rgb(255, 102, 128)">GitHub</a>
|
||||
</div>
|
||||
<TechnologyList />
|
||||
{#if posts}
|
||||
<Posts {posts} />
|
||||
{/if}
|
||||
|
|
@ -251,143 +73,12 @@
|
|||
background: white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.also > span {
|
||||
transition: color .3s;
|
||||
}
|
||||
.text-gray {
|
||||
color: rgb(150, 150, 150);
|
||||
}
|
||||
.text-gray img {
|
||||
filter: grayscale(70%);
|
||||
transition: filter .3s;
|
||||
}
|
||||
.text-white {
|
||||
color: black;
|
||||
}
|
||||
.dark .text-white {
|
||||
color: white;
|
||||
}
|
||||
main {
|
||||
margin: 0 min(50px, 5%) 0 min(50px, 5%);
|
||||
width: calc(100% - min(100px, 10%));
|
||||
}
|
||||
.projects {
|
||||
max-width: 1380px;
|
||||
}
|
||||
.projects {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 0 20px 0px 20px;
|
||||
}
|
||||
.also {
|
||||
margin: 50px auto 0 auto;
|
||||
max-width: 850px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.also h2 {
|
||||
margin-block-end: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.also > span {
|
||||
margin-bottom: 25px;
|
||||
display: block;
|
||||
}
|
||||
.split {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.split ul {
|
||||
min-width: 340px;
|
||||
margin: 0 auto;
|
||||
padding-left: 20px;
|
||||
list-style-type: none;
|
||||
}
|
||||
.also li {
|
||||
height: 32px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
cursor: pointer;
|
||||
transition: transform .3s, color .2s;
|
||||
}
|
||||
.also li:hover {
|
||||
color: black;
|
||||
}
|
||||
.also li:hover img {
|
||||
filter: grayscale(0%);
|
||||
}
|
||||
.dark .also li:hover {
|
||||
color: white;
|
||||
}
|
||||
.also li:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.also li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
left: -20px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 6px;
|
||||
background-color: black;
|
||||
transition: background-color .3s;
|
||||
}
|
||||
.dark .also li::before {
|
||||
background-color: white;
|
||||
}
|
||||
.also li img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
@media (min-width: 1520px) {
|
||||
.projects {
|
||||
margin: 0 auto 0px auto;
|
||||
}
|
||||
}
|
||||
.projects > div {
|
||||
width: calc(50% - 40px);
|
||||
}
|
||||
.projects .pad {
|
||||
margin-top: 110px;
|
||||
}
|
||||
@media (max-width: 860px) {
|
||||
.projects > div {
|
||||
width: calc(100% - 80px);
|
||||
margin: auto;
|
||||
}
|
||||
.projects .pad {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.projects h2 {
|
||||
margin: 1em 0 1em 10px;
|
||||
}
|
||||
}
|
||||
.projects h2 {
|
||||
font-size: 29px;
|
||||
font-weight: 400;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 40px;
|
||||
margin-inline-end: 40px;
|
||||
}
|
||||
h1 {
|
||||
color: #282B29;
|
||||
}
|
||||
h1 {
|
||||
font-size: 64px;
|
||||
}
|
||||
@media (max-width: 1100px) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# Hey there.
|
||||
# I don't think there's a valid vulnerability given this website is static, but I still put the file here just in case
|
||||
Contact: mailto:danbulant@danbulant.eu
|
||||
Contact: mailto:me@danbulant.eu
|
||||
Contact: matrix:@/:danbulant.cz
|
||||
Preferred-Languages: en, cs
|
||||
Canonical: https://danbulant.eu/.well-known/security.txt
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import HeroPost from "$lib/components/heroPost.svelte";
|
||||
import Post from "$lib/components/post.svelte";
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
import { flip } from 'svelte/animate';
|
||||
|
||||
var currentHover = null;
|
||||
|
|
@ -40,7 +39,7 @@
|
|||
</svelte:head>
|
||||
|
||||
|
||||
<div class="parent md:flex max-w-screen" class:dark={$darkmode}>
|
||||
<div class="parent md:flex max-w-screen">
|
||||
<h1 class="md:hidden">Posts</h1>
|
||||
|
||||
{#if tags}
|
||||
|
|
@ -92,7 +91,7 @@
|
|||
.tags {
|
||||
@apply flex flex-wrap gap-2 mt-2 mb-3;
|
||||
}
|
||||
.dark .tag {
|
||||
:global(.dark) .tag {
|
||||
background: rgb(77, 77, 77);
|
||||
}
|
||||
.tag {
|
||||
|
|
@ -100,7 +99,7 @@
|
|||
background: rgb(173, 173, 173);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.dark .tag.selected {
|
||||
:global(.dark) .tag.selected {
|
||||
background: rgb(0, 108, 170);
|
||||
}
|
||||
.tag.selected {
|
||||
|
|
@ -114,7 +113,7 @@
|
|||
border: none;
|
||||
background: black;
|
||||
}
|
||||
.dark hr {
|
||||
:global(.dark) hr {
|
||||
background: white;
|
||||
}
|
||||
small {
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ export async function GET(req) {
|
|||
return new Date(b.date) - new Date(a.date)
|
||||
});
|
||||
|
||||
// the best XML library ever
|
||||
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Blog - Daniel Bulant</title>
|
||||
<description>My personal blog about work, programming and fun stuff.</description>
|
||||
<link>https://danbulant.eu/posts</link>
|
||||
<copyright>2022 Daniel Bulant</copyright>
|
||||
<copyright>2023 Daniel Bulant</copyright>
|
||||
<pubDate>${new Date().toUTCString()}</pubDate>
|
||||
<ttl>180</ttl>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,18 @@ description: Rust is a fast memory-safe low level programming language. And here
|
|||
|
||||
<script>
|
||||
import Callout from "$lib/components/posts/callout.svelte";
|
||||
import { browser } from "$app/environment";
|
||||
|
||||
var story = true;
|
||||
</script>
|
||||
|
||||
*I seem to like storytelling a bit too much.*
|
||||
<div style="display: flex; align-items: center;">
|
||||
<label for="enable_story" style="padding-right: 10px">Enable story</label>
|
||||
<input type="checkbox" style="padding: 0; margin: 0;" bind:checked={story} id="enable_story">
|
||||
</div>
|
||||
{#if browser}
|
||||
*I seem to like storytelling a bit too much.*
|
||||
<div style="display: flex; align-items: center;">
|
||||
<label for="enable_story" style="padding-right: 10px">Enable story</label>
|
||||
<input type="checkbox" style="padding: 0; margin: 0;" bind:checked={story} id="enable_story">
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
> I really do enjoy reading blog posts like these, so I figured I'd try writing few of my own as well. I hope you'll enjoy it, if so, leave a comment below.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
<script>
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
var name = "world";
|
||||
</script>
|
||||
|
||||
<input class:dark={$darkmode} type=text bind:value={name} class="text-black">
|
||||
<input type=text bind:value={name} class="text-black">
|
||||
|
||||
<=>
|
||||
|
||||
<input class:dark={$darkmode} type=text bind:value={name} class="text-black">
|
||||
<input type=text bind:value={name} class="text-black">
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
input {
|
||||
@apply p-2 bg-transparent backdrop-blur my-2 transition-colors duration-150;
|
||||
border: none;
|
||||
|
|
@ -18,10 +17,10 @@
|
|||
input:focus {
|
||||
@apply outline-none border-b-black/70;
|
||||
}
|
||||
input.dark {
|
||||
:global(.dark) input {
|
||||
@apply border-b-white/30 text-white;
|
||||
}
|
||||
input.dark:focus {
|
||||
:global(.dark) input:focus {
|
||||
@apply border-b-white/70;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
<script>
|
||||
import darkmode from "$lib/stores/darkmode";
|
||||
|
||||
var name = "world";
|
||||
|
||||
let funny = { "amogus": "ඞ", "AMOGUS": "sussy baka", "discord": "proprietary matrix", "never gonna give you up": "never gonna let you down", "wysi": "727", "727": "wysi" };
|
||||
|
|
@ -8,9 +6,9 @@
|
|||
|
||||
<h1>Hello {funny[name] || name}</h1>
|
||||
|
||||
<input class:dark={$darkmode} type=text class="text-black" bind:value={name}>
|
||||
<input type=text class="text-black" bind:value={name}>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
h1 {
|
||||
@apply p-0 m-0 text-xl font-bold;
|
||||
}
|
||||
|
|
@ -22,10 +20,10 @@
|
|||
input:focus {
|
||||
@apply outline-none border-b-black/70;
|
||||
}
|
||||
input.dark {
|
||||
:global(.dark) input {
|
||||
@apply border-b-white/30 text-white;
|
||||
}
|
||||
input.dark:focus {
|
||||
:global(.dark) input:focus {
|
||||
@apply border-b-white/70;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
BIN
static/screenshots/heaventaker/characters.png
Normal file
BIN
static/screenshots/heaventaker/characters.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
BIN
static/screenshots/heaventaker/heaven.png
Normal file
BIN
static/screenshots/heaventaker/heaven.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 316 KiB |
BIN
static/screenshots/heaventaker/uriel.png
Normal file
BIN
static/screenshots/heaventaker/uriel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 728 KiB |
BIN
static/screenshots/tictactoe.png
Normal file
BIN
static/screenshots/tictactoe.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
Loading…
Reference in a new issue