Massive refactor: integrate Tailwind, use components, data-driven lists
This is the result of many, many hours sat at my keyboard trying different things, most of which failing. Figuring out how to install Tailwind in this setup was a real adventure with all of the resources online pulling me in two different ways. Documentation is hard. I definitely do prefer having the codebase use the tools available more, instead of the old simple web dev stuff I'm used to. We're using what's available through Svelte a lot more now. I think that these changes will make the codebase easier to work in, with the architecture being more familiar to regular web developers, and these changes should also reduce friction when adding new content, which is the main goal. I'll never get this time back though, and I'm still slightly contemplating whether it was really worth it.
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
|
@ -15,15 +15,20 @@
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.13",
|
||||
"sass": "^1.83.4",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"bootstrap-icons": "^1.11.3"
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
darkTheme;
|
||||
|
||||
for (let i = 0; i < gradients.length; i++) {
|
||||
// This re-renders each gradient so their new color will be correct
|
||||
// This recolors each gradient so their new color will be correct
|
||||
let gradient = gradients[i];
|
||||
gradient.color = getRandomColor();
|
||||
gradient.prepareBuffer();
|
17
src/blocks/footer.svelte
Normal file
17
src/blocks/footer.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<span
|
||||
class="mx-auto flex w-[95%] flex-col border-t
|
||||
border-t-[var(--text-color)] p-1 text-center lg:flex-row lg:justify-between"
|
||||
>
|
||||
<p class="py-4 lg:px-[10%]">
|
||||
© 2025 Colormatic Studios, All Rights Reserved.
|
||||
</p>
|
||||
<p class="py-4 lg:px-[10%]">
|
||||
<a href="mailto:support@colormatic.org" class="underline">
|
||||
support@colormatic.org
|
||||
</a>
|
||||
<span class="hidden lg:inline">|</span>
|
||||
<a href="mailto:contact@colormatic.org" class="underline">
|
||||
contact@colormatic.org
|
||||
</a>
|
||||
</p>
|
||||
</span>
|
206
src/blocks/navbar.svelte
Normal file
206
src/blocks/navbar.svelte
Normal file
@ -0,0 +1,206 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
|
||||
let modal = $state() as HTMLElement;
|
||||
let modalOpenState = $state(false);
|
||||
|
||||
function toggleModalMenu() {
|
||||
modalOpenState = !modalOpenState;
|
||||
}
|
||||
|
||||
function modalHandleClickOutside(e: MouseEvent) {
|
||||
if (e.target == modal) {
|
||||
toggleModalMenu();
|
||||
}
|
||||
}
|
||||
|
||||
let darkTheme: CallableFunction = getContext("darkTheme");
|
||||
</script>
|
||||
|
||||
<nav
|
||||
class="mx-auto box-border grid w-[95%] grid-cols-[1fr_min-content_1fr]
|
||||
items-center border-b border-b-[var(--text-color)] p-2 wrap-anywhere lg:p-3"
|
||||
>
|
||||
<a href="/" class="justify-self-start text-[140%] font-bold">Colormatic</a>
|
||||
<img
|
||||
src="/img/colormatic_logo.svg"
|
||||
alt="Colormatic Logo"
|
||||
class="h-[40px] max-w-[unset]"
|
||||
/>
|
||||
<div class="flex justify-self-end">
|
||||
<ul
|
||||
class="responsive-hidden hidden
|
||||
flex-row lg:flex"
|
||||
>
|
||||
<!-- prettier-ignore -->
|
||||
{#each [
|
||||
{
|
||||
label: "Zakarya",
|
||||
link: "/zakarya"
|
||||
},
|
||||
{
|
||||
label: "Colormatic Studios",
|
||||
link: "/studios"
|
||||
},
|
||||
{
|
||||
label: "About",
|
||||
link: "/about"
|
||||
}
|
||||
] as item}
|
||||
<li><a href={item.link}>{item.label}</a></li>
|
||||
{/each}
|
||||
</ul>
|
||||
<a
|
||||
href="https://git.colormatic.org"
|
||||
class="git-icon"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Colormatic Git"
|
||||
>
|
||||
<i class="bi bi-git text-[160%]"></i>
|
||||
</a>
|
||||
<button onclick={toggleModalMenu} class="menu-button" aria-label="menu">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!--
|
||||
The following Svelte ignore statements aren't ideal, but it seems to be
|
||||
the only way to achieve a proper modal. They even do this in the
|
||||
Svelte modal example, https://svelte.dev/playground/modal
|
||||
-->
|
||||
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
||||
<span
|
||||
onclick={modalHandleClickOutside}
|
||||
bind:this={modal}
|
||||
class="fixed top-0 left-0 z-1 m-auto h-full w-full bg-[#00000066]
|
||||
{modalOpenState ? '' : 'hidden'}"
|
||||
>
|
||||
<div
|
||||
class="modal-animate mx-auto mt-[100px] w-[30ch] rounded-lg p-4
|
||||
shadow-[1px_1px_8px_#00000033] backdrop-blur-[5px] lg:w-[50ch]
|
||||
{darkTheme() ? 'bg-[#000000bb]' : 'bg-[#ffffff88]'}"
|
||||
>
|
||||
<button
|
||||
onclick={toggleModalMenu}
|
||||
class="float-right w-min cursor-pointer text-[200%] text-[var(--text-color)]
|
||||
duration-[0.2s] hover:text-[#21afff]"
|
||||
aria-label="Close"
|
||||
>
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
<ul>
|
||||
<!-- prettier-ignore -->
|
||||
{#each [
|
||||
{
|
||||
label: "Home",
|
||||
link: "/",
|
||||
newTab: false
|
||||
},
|
||||
{
|
||||
label: "Zakarya",
|
||||
link: "/zakarya",
|
||||
newTab: false
|
||||
},
|
||||
{
|
||||
label: "Colormatic Studios",
|
||||
link: "/studios",
|
||||
newTab: false
|
||||
},
|
||||
{
|
||||
label: "Colormatic Git",
|
||||
link: "https://git.colormatic.org",
|
||||
newTab: true
|
||||
},
|
||||
{
|
||||
label: "Colormatic ID",
|
||||
link: "https://auth.colormatic.org",
|
||||
newTab: true
|
||||
},
|
||||
{
|
||||
label: "About",
|
||||
link: "/about",
|
||||
newTab: false
|
||||
}
|
||||
] as item}
|
||||
|
||||
<li class="mx-[12px] my-[18px]">
|
||||
{#if item.newTab}
|
||||
<a
|
||||
href="{item.link}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-color p-2 text-[120%]"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
{:else}
|
||||
<a
|
||||
href="{item.link}"
|
||||
class="text-color p-2 text-[120%]"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
nav a,
|
||||
nav button {
|
||||
padding: 0 8px;
|
||||
color: var(--text-color);
|
||||
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav button.menu-button {
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
nav button.menu-button:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
nav .menu-button i {
|
||||
font-size: 230%;
|
||||
|
||||
/*/
|
||||
* Ugly hack to account for the fact that the menu icon is off-center
|
||||
* (Bootstrap please fix)
|
||||
/*/
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/*/
|
||||
* Navigation modal section
|
||||
/*/
|
||||
|
||||
div.modal-animate {
|
||||
animation-name: modal-animate-in;
|
||||
animation-duration: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes modal-animate-in {
|
||||
from {
|
||||
transform: translate(0px, -300px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translate(0px, 0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -2,6 +2,7 @@
|
||||
import { getContext, onMount } from "svelte";
|
||||
import { themes } from "../script/theme.ts";
|
||||
import { setCookie, getCookie } from "../script/cookie.ts";
|
||||
import Panel from "components/panel.svelte";
|
||||
|
||||
let panelRef = $state() as HTMLElement;
|
||||
|
||||
@ -64,95 +65,61 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={panelRef}
|
||||
class="theme-toggle panel {darkTheme() ? 'dark-theme' : ''}"
|
||||
>
|
||||
<button
|
||||
class="toggle-button"
|
||||
onclick={togglePanel}
|
||||
aria-label="Toggle Theme Selector"
|
||||
>
|
||||
<i class={`bi ${currentIcon}`}></i>
|
||||
</button>
|
||||
<div bind:this={panelRef} class="fixed right-5 bottom-5 flex">
|
||||
<Panel className="flex flex-col-reverse p-1">
|
||||
<button
|
||||
class="flex cursor-pointer items-center px-[5px] text-[1.3rem]"
|
||||
onclick={togglePanel}
|
||||
aria-label="Toggle Theme Selector"
|
||||
>
|
||||
<i class={`bi ${currentIcon}`}></i>
|
||||
</button>
|
||||
|
||||
<!-- Unfortunately, we have to hard-code the pixel count because CSS won't animate `auto` or `min-content` -->
|
||||
<div class="button-group" style:height={expanded ? "68px" : "0px"}>
|
||||
<!-- Don't show the button if it is currently selected (it will be shown as the dropdown icon) -->
|
||||
{#if themeOption !== themes.DARK}
|
||||
<button
|
||||
aria-label="Dark Theme"
|
||||
bind:this={darkButton}
|
||||
onclick={() => setThemeOption(themes.DARK)}
|
||||
>
|
||||
<i bind:this={darkButtonIcon} class="bi bi-moon"></i>
|
||||
</button>
|
||||
{/if}
|
||||
<!-- Unfortunately, we have to hard-code the pixel count because CSS won't animate `auto` or `min-content` -->
|
||||
<div
|
||||
class="button-group flex flex-col overflow-hidden"
|
||||
style:height={expanded ? "68px" : "0px"}
|
||||
>
|
||||
<!-- Don't show the button if it is currently selected (it will be shown as the dropdown icon) -->
|
||||
{#if themeOption !== themes.DARK}
|
||||
<button
|
||||
aria-label="Dark Theme"
|
||||
bind:this={darkButton}
|
||||
onclick={() => setThemeOption(themes.DARK)}
|
||||
class="cursor-pointer text-[1.3rem]"
|
||||
>
|
||||
<i bind:this={darkButtonIcon} class="bi bi-moon"></i>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if themeOption !== themes.LIGHT}
|
||||
<button
|
||||
aria-label="Light Theme"
|
||||
bind:this={lightButton}
|
||||
onclick={() => setThemeOption(themes.LIGHT)}
|
||||
>
|
||||
<i bind:this={lightButtonIcon} class="bi bi-sun"></i>
|
||||
</button>
|
||||
{/if}
|
||||
{#if themeOption !== themes.LIGHT}
|
||||
<button
|
||||
aria-label="Light Theme"
|
||||
bind:this={lightButton}
|
||||
class="cursor-pointer text-[1.3rem]"
|
||||
onclick={() => setThemeOption(themes.LIGHT)}
|
||||
>
|
||||
<i bind:this={lightButtonIcon} class="bi bi-sun"></i>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if themeOption !== themes.AUTO}
|
||||
<button
|
||||
aria-label="Auto Theme"
|
||||
bind:this={autoButton}
|
||||
onclick={() => setThemeOption(themes.AUTO)}
|
||||
>
|
||||
<i bind:this={autoButtonIcon} class="bi bi-circle-half"></i>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if themeOption !== themes.AUTO}
|
||||
<button
|
||||
aria-label="Auto Theme"
|
||||
bind:this={autoButton}
|
||||
class="cursor-pointer text-[1.3rem]"
|
||||
onclick={() => setThemeOption(themes.AUTO)}
|
||||
>
|
||||
<i bind:this={autoButtonIcon} class="bi bi-circle-half"></i>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../style/global.scss";
|
||||
|
||||
div.theme-toggle {
|
||||
padding: 4px;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
button.toggle-button {
|
||||
font-size: 1.3rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: global.$text-color;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
div.button-group {
|
||||
overflow: hidden;
|
||||
transition: height 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.button-group button {
|
||||
margin: 2px 0;
|
||||
font-size: 1.3rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: global.$text-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
div.button-group button {
|
||||
margin: 4px 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Click target color animation
|
@ -1,42 +0,0 @@
|
||||
<footer>
|
||||
<p>© 2025 Colormatic Studios, All Rights Reserved.</p>
|
||||
<p>
|
||||
<a href="mailto:support@colormatic.org">support@colormatic.org</a>
|
||||
<span class="responsive-hidden">|</span>
|
||||
<a href="mailto:contact@colormatic.org">contact@colormatic.org</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../style/global.scss";
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-top: solid 1px global.$text-color;
|
||||
width: 95%;
|
||||
padding: 4px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
footer p {
|
||||
color: global.$text-color;
|
||||
padding: 4px 10%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
footer p {
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.responsive-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,287 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
|
||||
let pages = $state() as HTMLElement;
|
||||
|
||||
function toggleModalMenu() {
|
||||
pages.classList.toggle("hidden");
|
||||
}
|
||||
function modalMenuProcessClick(e: MouseEvent) {
|
||||
if (e.target == pages) {
|
||||
pages.classList.toggle("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
let darkTheme: CallableFunction = getContext("darkTheme");
|
||||
</script>
|
||||
|
||||
<nav>
|
||||
<a href="/" class="title nav-left">Colormatic</a>
|
||||
<img
|
||||
src="/img/colormatic_logo.svg"
|
||||
alt="Colormatic Logo"
|
||||
class="nav-center colormatic-logo"
|
||||
/>
|
||||
<div class="nav-right inline">
|
||||
<ul class="responsive-hidden">
|
||||
<li><a href="/zakarya">Zakarya</a></li>
|
||||
<li><a href="/studios">Colormatic Studios</a></li>
|
||||
<li><a href="/about">About</a></li>
|
||||
</ul>
|
||||
<a
|
||||
href="https://git.colormatic.org"
|
||||
class="git-icon"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Colormatic Git"
|
||||
>
|
||||
<i class="bi bi-git"></i>
|
||||
</a>
|
||||
<button onclick={toggleModalMenu} class="menu-button" aria-label="menu">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!--
|
||||
The following Svelte ignore statements aren't ideal, but it seems to be
|
||||
the only way to achieve a proper modal. They even do this in the
|
||||
Svelte modal example, https://svelte.dev/playground/modal
|
||||
-->
|
||||
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
||||
<span onclick={modalMenuProcessClick} bind:this={pages} class="modalbg hidden">
|
||||
<div class={darkTheme() ? "dark-theme" : ""}>
|
||||
<button onclick={toggleModalMenu} class="close" aria-label="Close">
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/zakarya">Zakarya</a></li>
|
||||
<li><a href="/studios">Colormatic Studios</a></li>
|
||||
<li>
|
||||
<a
|
||||
href="https://git.colormatic.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Colormatic Git
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://auth.colormatic.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Colormatic ID
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="/about">About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../style/global.scss";
|
||||
|
||||
nav {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr min-content 1fr;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
border-bottom: solid 1px global.$text-color;
|
||||
z-index: 1;
|
||||
|
||||
margin: 0 auto;
|
||||
width: 95%;
|
||||
box-sizing: border-box;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
nav .nav-left {
|
||||
justify-self: left;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
nav .nav-center {
|
||||
justify-self: center;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
nav .nav-right {
|
||||
justify-self: right;
|
||||
grid-column: 3;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
nav a,
|
||||
nav button {
|
||||
padding: 0 8px;
|
||||
color: global.$text-color;
|
||||
text-decoration: none;
|
||||
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav a.title {
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
nav img.colormatic-logo {
|
||||
width: auto;
|
||||
height: 40px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
nav button.menu-button {
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
nav button.menu-button:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
nav .menu-button i {
|
||||
font-size: 230%;
|
||||
|
||||
/*/
|
||||
* Ugly hack to account for the fact that the menu icon is off-center
|
||||
* (Bootstrap please fix)
|
||||
/*/
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
nav .git-icon i {
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
nav div.inline {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
nav {
|
||||
padding: 6px 0;
|
||||
}
|
||||
nav .git-icon i {
|
||||
font-size: 150%;
|
||||
}
|
||||
nav ul.responsive-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*/
|
||||
* Navigation modal section
|
||||
/*/
|
||||
|
||||
span.modalbg.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
span.modalbg {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
span.modalbg div {
|
||||
width: 50ch;
|
||||
margin: 100px auto;
|
||||
padding: 16px;
|
||||
|
||||
color: global.$text-color;
|
||||
border-radius: 8px;
|
||||
box-shadow: 1px 1px 8px #00000033;
|
||||
background-color: #ffffffbb;
|
||||
backdrop-filter: blur(5px);
|
||||
|
||||
animation-name: modal-animate-in;
|
||||
animation-duration: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes modal-animate-in {
|
||||
from {
|
||||
transform: translate(0px, -300px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translate(0px, 0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
span.modalbg div button.close {
|
||||
float: right;
|
||||
width: min-content;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
font-size: 200%;
|
||||
color: global.$text-color;
|
||||
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
span.modalbg div button.close:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
span.modalbg div ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
span.modalbg div ul li {
|
||||
margin: 18px 12px;
|
||||
}
|
||||
|
||||
span.modalbg div ul li a {
|
||||
color: global.$text-color;
|
||||
padding: 8px;
|
||||
text-decoration: none;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
span.modalbg div ul li a:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
span.modalbg div {
|
||||
width: 30ch;
|
||||
}
|
||||
}
|
||||
|
||||
span.modalbg div.dark-theme {
|
||||
background-color: #000000bb;
|
||||
}
|
||||
</style>
|
1
src/components/divider.svelte
Normal file
1
src/components/divider.svelte
Normal file
@ -0,0 +1 @@
|
||||
<div class="m-[24px] border-t border-t-[var(--text-color)]"></div>
|
16
src/components/hero.svelte
Normal file
16
src/components/hero.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import Panel from "components/panel.svelte";
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
children?: import("svelte").Snippet;
|
||||
}
|
||||
let { className, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<Panel
|
||||
className="mx-auto my-4 w-[90%] lg:w-[60%] p-6 text-center
|
||||
{className}"
|
||||
>
|
||||
{@render children?.()}
|
||||
</Panel>
|
40
src/components/linktree.svelte
Normal file
40
src/components/linktree.svelte
Normal file
@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
className?: string;
|
||||
links: {
|
||||
label: string;
|
||||
url: string;
|
||||
}[];
|
||||
}
|
||||
let { className, links }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ul
|
||||
class="{className}"
|
||||
>
|
||||
{#each links as link}
|
||||
<li class="my-3 text-center">
|
||||
<a
|
||||
class="box-border inline-block w-full rounded-full
|
||||
bg-[#4c5053] px-4 py-2 no-underline
|
||||
shadow-[2px_2px_4px_#00000066] transition duration-500 hover:bg-[#383c3f]"
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<style lang="scss">
|
||||
/*/
|
||||
* This may look out of place, but the background color of the links
|
||||
* in the link tree don't change based on light/dark theme. The text
|
||||
* color of the links should always be white.
|
||||
/*/
|
||||
ul li a {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
20
src/components/panel.svelte
Normal file
20
src/components/panel.svelte
Normal file
@ -0,0 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
|
||||
let darkTheme: CallableFunction = getContext("darkTheme");
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
children?: import("svelte").Snippet;
|
||||
}
|
||||
let { className, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="rounded-[8px] border bg-[#ffffff22]
|
||||
shadow-[1px_1px_8px_#00000033] backdrop-blur-[5px]
|
||||
{className}
|
||||
{darkTheme() ? 'border-[#ffffff33]' : 'border-[#00000033]'}"
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
12
src/components/spacer.svelte
Normal file
12
src/components/spacer.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<span class="spacer"></span>
|
||||
|
||||
<style lang="scss">
|
||||
span.spacer {
|
||||
display: block;
|
||||
margin-top: 24%;
|
||||
|
||||
@media (width >= 64rem) {
|
||||
margin-top: 8%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import "../style/main.scss";
|
||||
import "style/main.scss";
|
||||
import "style/tailwind.css";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import Navbar from "../component/navbar.svelte";
|
||||
import Footer from "../component/footer.svelte";
|
||||
import Bg from "../component/bg.svelte";
|
||||
import Settings from "../component/settings.svelte";
|
||||
import { themes } from "../script/theme.ts";
|
||||
import Navbar from "blocks/navbar.svelte";
|
||||
import Footer from "blocks/footer.svelte";
|
||||
import Bg from "blocks/bg.svelte";
|
||||
import Settings from "blocks/settings.svelte";
|
||||
import { themes } from "script/theme.ts";
|
||||
import { onMount, setContext } from "svelte";
|
||||
|
||||
interface Props {
|
||||
|
@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from "svelte";
|
||||
import Spacer from "components/spacer.svelte";
|
||||
import Hero from "components/hero.svelte";
|
||||
import Divider from "components/divider.svelte";
|
||||
|
||||
let atTop = $state(true);
|
||||
|
||||
@ -44,9 +47,12 @@
|
||||
<meta property="og:type" content="website" />
|
||||
</svelte:head>
|
||||
|
||||
<main class={darkTheme() ? "dark-theme" : ""}>
|
||||
<div class="brand-heading">
|
||||
<h1>Colormatic: A non-profit project for creation.</h1>
|
||||
<main>
|
||||
<div
|
||||
class="px-[12px] py-[38%] text-center text-[300%] font-bold
|
||||
lg:w-[70%] lg:p-[12%] lg:text-left lg:text-[350%]"
|
||||
>
|
||||
Colormatic: A non-profit project for creation.
|
||||
</div>
|
||||
|
||||
<div class="scroll-arrow {atTop ? '' : 'hide'}">
|
||||
@ -55,84 +61,80 @@
|
||||
|
||||
<div style="margin-top:calc(100vh - 500px);"></div>
|
||||
|
||||
<div class="heading">Featured Colormatic Studios Projects:</div>
|
||||
<div class="hero panel">
|
||||
<h1>
|
||||
<a
|
||||
href="https://git.colormatic.org/ColormaticStudios/quality-godot-first-person"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Quality First Person Controller
|
||||
</a>
|
||||
</h1>
|
||||
<p>An actually good first person controller for the Godot Engine.</p>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<h1>
|
||||
<a
|
||||
href="https://git.colormatic.org/ColormaticStudios/godot-bson"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
BSON for Godot
|
||||
</a>
|
||||
</h1>
|
||||
<p>A BSON serializer/deserializer for the Godot Engine</p>
|
||||
<div class="p-3 text-center text-[250%]">
|
||||
Featured Colormatic Studios Projects:
|
||||
</div>
|
||||
<Hero>
|
||||
<!--
|
||||
Prettier wants to pack all of this data into one line, probably a bug.
|
||||
This must be formatted manually.
|
||||
|
||||
<spacer></spacer>
|
||||
This issue happens in various places around the codebase, whenever we
|
||||
stuff data directly into an #each statement. This is the most prominent
|
||||
place though, so I'll stick this comment here.
|
||||
|
||||
<div class="hero panel">
|
||||
<h1>
|
||||
<i class="bi bi-tools" style="padding-right: 12px;"></i>
|
||||
Notice that Prettier also won't format the code inside the #each statement,
|
||||
which means that the Tailwind classes won't get sorted. I'll miss that
|
||||
feature.
|
||||
-->
|
||||
<!-- prettier-ignore -->
|
||||
{#each [
|
||||
{
|
||||
title: "Quality First Person Controller",
|
||||
link: "https://git.colormatic.org/ColormaticStudios/quality-godot-first-person",
|
||||
description: "An actually good first person controller for the Godot Engine."
|
||||
},
|
||||
{
|
||||
title: "BSON for Godot",
|
||||
link: "https://git.colormatic.org/ColormaticStudios/godot-bson",
|
||||
description: "A BSON serializer/deserializer for the Godot Engine"
|
||||
}
|
||||
] as item, index}
|
||||
|
||||
{#if index !== 0}
|
||||
<Divider />
|
||||
{/if}
|
||||
|
||||
<a
|
||||
href={item.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-color text-[200%] font-bold underline"
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
<p class="pt-3">{item.description}</p>
|
||||
{/each}
|
||||
</Hero>
|
||||
|
||||
<Spacer />
|
||||
|
||||
<Hero>
|
||||
<span class="text-[200%] font-bold">
|
||||
<i class="bi bi-tools pr-3"></i>
|
||||
This website is under construction.
|
||||
</h1>
|
||||
<p>
|
||||
</span>
|
||||
<p class="p-3">
|
||||
Check up on progress and changes at <a
|
||||
href="https://git.colormatic.org/ColormaticStudios/Colormatic-Website"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="underline"
|
||||
>
|
||||
ColormaticStudios/Colormatic-Website
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</Hero>
|
||||
</main>
|
||||
|
||||
<spacer></spacer>
|
||||
<Spacer />
|
||||
|
||||
<style lang="scss">
|
||||
@use "../style/global.scss";
|
||||
|
||||
main div.brand-heading {
|
||||
padding: 12%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
main div.brand-heading h1 {
|
||||
font-size: 300%;
|
||||
}
|
||||
|
||||
main div.heading {
|
||||
font-size: 250%;
|
||||
text-align: center;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
main div.brand-heading {
|
||||
padding: 38% 12px;
|
||||
text-align: center;
|
||||
width: initial;
|
||||
}
|
||||
|
||||
main div.heading {
|
||||
font-size: 200%;
|
||||
}
|
||||
}
|
||||
|
||||
/*/
|
||||
* Yes, this isn't in Tailwind, but I really don't want to translate this
|
||||
* animation because Tailwind animations are stupidly verbose. With that,
|
||||
* I also didn't translate the CSS around it because I just don't want to.
|
||||
/*/
|
||||
main div.scroll-arrow {
|
||||
text-align: center;
|
||||
font-size: 200%;
|
||||
|
@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Hero from "components/hero.svelte";
|
||||
import Spacer from "components/spacer.svelte";
|
||||
import { getContext } from "svelte";
|
||||
|
||||
let darkTheme: CallableFunction = getContext("darkTheme");
|
||||
@ -26,27 +28,29 @@
|
||||
<meta property="og:type" content="website" />
|
||||
</svelte:head>
|
||||
|
||||
<spacer></spacer>
|
||||
<Spacer />
|
||||
|
||||
<main class={darkTheme() ? "dark-theme" : ""}>
|
||||
<div class="hero panel">
|
||||
<h1>Colormatic: A non-profit project for creation.</h1>
|
||||
<p class="justify">
|
||||
<main>
|
||||
<Hero>
|
||||
<span class="text-[200%] font-bold">
|
||||
Colormatic: A non-profit project for creation.
|
||||
</span>
|
||||
<p class="justify pt-3">
|
||||
Colormatic is a non-profit project from Zakarya for creating a curated
|
||||
collection of sub-projects that match a high-quality, high attention to
|
||||
detail standard.
|
||||
</p>
|
||||
<p class="justify">
|
||||
<p class="justify pt-3">
|
||||
Colormatic is still in the early stages, so expect many things to change
|
||||
in the near future.
|
||||
</p>
|
||||
<p class="justify">
|
||||
<p class="justify pt-3">
|
||||
Colormatic Studios is a creative studio dedicated to giving life to
|
||||
Colormatic's projects. We are currently just a small group of passionate
|
||||
volunteers working to build inspiring, intuitive and innovative creative
|
||||
works.
|
||||
</p>
|
||||
</div>
|
||||
</Hero>
|
||||
</main>
|
||||
|
||||
<spacer></spacer>
|
||||
<Spacer />
|
||||
|
@ -1,4 +1,8 @@
|
||||
<script lang="ts">
|
||||
import Panel from "components/panel.svelte";
|
||||
import Hero from "components/hero.svelte";
|
||||
import Spacer from "components/spacer.svelte";
|
||||
import Linktree from "components/linktree.svelte";
|
||||
import { getContext } from "svelte";
|
||||
|
||||
let darkTheme: CallableFunction = getContext("darkTheme");
|
||||
@ -35,244 +39,142 @@
|
||||
<meta property="og:type" content="website" />
|
||||
</svelte:head>
|
||||
|
||||
<main class={darkTheme() ? "dark-theme" : ""}>
|
||||
<div class="cs-title"><h1>Colormatic Studios</h1></div>
|
||||
|
||||
<div class="project-grid-container">
|
||||
<div class="project-grid-box panel">
|
||||
<h1>
|
||||
<a
|
||||
href="https://git.colormatic.org/ColormaticStudios/quality-godot-first-person"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Quality First Person Controller
|
||||
</a>
|
||||
</h1>
|
||||
<div class="project-grid-box-contents">
|
||||
<img
|
||||
src="https://git.colormatic.org/ColormaticStudios/quality-godot-first-person/raw/branch/main/icon.svg"
|
||||
alt="First Person Logo"
|
||||
/>
|
||||
<p>An actually good first person controller for the Godot Engine.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-grid-box panel">
|
||||
<h1>
|
||||
<a
|
||||
href="https://git.colormatic.org/ColormaticStudios/godot-bson"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
BSON for Godot
|
||||
</a>
|
||||
</h1>
|
||||
<div class="project-grid-box-contents">
|
||||
<img
|
||||
src="https://git.colormatic.org/ColormaticStudios/godot-bson/raw/branch/main/icon.svg"
|
||||
alt="Godot BSON Logo"
|
||||
/>
|
||||
<p>A BSON serializer/deserializer for the Godot Engine.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-grid-box panel">
|
||||
<h1>A Silly Game</h1>
|
||||
<div class="project-grid-box-contents">
|
||||
<img src="/img/studios/hatcat.webp" alt="HatCat" />
|
||||
<p>
|
||||
This is a silly little game project to get us started.
|
||||
<br />
|
||||
Currently in closed pre-alpha.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-grid-box panel">
|
||||
<h1>ColorQuest</h1>
|
||||
<div class="project-grid-box-contents">
|
||||
<img
|
||||
src="/img/studios/colorquest.png"
|
||||
class="pixelart"
|
||||
alt="ColorQuest"
|
||||
/>
|
||||
<p>
|
||||
A simple browser MMORPG focused on social features.
|
||||
<br />
|
||||
Currently in closed pre-alpha.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<main>
|
||||
<div
|
||||
class="cs-title flex h-[200px] items-center justify-center bg-cover lg:h-[300px]"
|
||||
>
|
||||
<span
|
||||
class="rounded-2xl bg-[#00000088] px-[38px] py-[28px] text-[200%] font-bold
|
||||
text-white shadow-[1px_1px_8px_#00000033] backdrop-blur-[5px] lg:text-[300%]"
|
||||
>
|
||||
Colormatic Studios
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="hero panel">
|
||||
<h1>About Us</h1>
|
||||
<p class="justify">
|
||||
<div class="mx-auto flex w-[90%] flex-col flex-wrap lg:w-[80%] lg:flex-row">
|
||||
<!-- prettier-ignore -->
|
||||
{#each [
|
||||
{
|
||||
title: "Quality First Person Controller",
|
||||
link: "https://git.colormatic.org/ColormaticStudios/quality-godot-first-person",
|
||||
description: "An actually good first person controller for the Godot Engine.",
|
||||
image: "https://git.colormatic.org/ColormaticStudios/quality-godot-first-person/raw/branch/main/icon.svg",
|
||||
pixelArt: false
|
||||
},
|
||||
{
|
||||
title: "BSON for Godot",
|
||||
link: "https://git.colormatic.org/ColormaticStudios/godot-bson",
|
||||
description: "A BSON serializer/deserializer for the Godot Engine.",
|
||||
image: "https://git.colormatic.org/ColormaticStudios/godot-bson/raw/branch/main/icon.svg",
|
||||
pixelArt: false
|
||||
},
|
||||
{
|
||||
title: "A Silly Game",
|
||||
link: "",
|
||||
description: "This is a silly little game project to get us started. Currently in closed pre-alpha.",
|
||||
image: "/img/studios/hatcat.webp",
|
||||
pixelArt: false
|
||||
},
|
||||
{
|
||||
title: "ColorQuest",
|
||||
link: "",
|
||||
description: "A simple browser MMORPG focused on social features. Currently in closed pre-alpha.",
|
||||
image: "/img/studios/colorquest.png",
|
||||
pixelArt: true
|
||||
}
|
||||
] as item}
|
||||
|
||||
<Panel className="flex-1 my-2 lg:m-4 lg:min-w-[40%] lg:max-w-[50%] p-4">
|
||||
<div class="p-4">
|
||||
{#if item.link}
|
||||
<a
|
||||
href="{item.link}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-color underline text-center text-[200%] font-bold block"
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
{:else}
|
||||
<span class="text-center text-[200%] font-bold block">{item.title}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex">
|
||||
<img
|
||||
src="{item.image}"
|
||||
alt="First Person Logo"
|
||||
class="max-w-[120px] max-h-[150px] m-3 rounded-lg
|
||||
{item.pixelArt ? 'pixelart' : ''}"
|
||||
/>
|
||||
<p class="pt-4">{item.description}</p>
|
||||
</div>
|
||||
</Panel>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<Hero>
|
||||
<span class="text-[200%] font-bold">About Us</span>
|
||||
<p class="justify pt-3">
|
||||
Colormatic Studios is a creative studio dedicated to giving life to
|
||||
Colormatic's ambitious future.
|
||||
</p>
|
||||
<p class="justify">
|
||||
<p class="justify pt-3">
|
||||
We are currently just a passionate team of volunteers working to build
|
||||
inspiring, intuitive and innovative creative works. We don't have many
|
||||
projects right now, but we're working hard behind the scenes on ventures
|
||||
we'll be introducing later.
|
||||
inspiring, intuitive and innovative creative works. We don't have much to
|
||||
show right now, but we're working hard behind the scenes on projects we'll
|
||||
be introducing later.
|
||||
</p>
|
||||
</div>
|
||||
</Hero>
|
||||
|
||||
<div class="hero panel">
|
||||
<h1>Links:</h1>
|
||||
<div class="double-linktree">
|
||||
<ul class="linktree">
|
||||
<li>
|
||||
<a
|
||||
href="https://mastodon.social/@colormaticstudios"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Mastodon
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://www.instagram.com/colormaticstudios/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Instagram
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://www.youtube.com/@colormaticstudios"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Youtube
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="linktree">
|
||||
<li>
|
||||
<a
|
||||
href="https://git.colormatic.org/ColormaticStudios"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Colormatic Git
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/ColormaticStudios"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://bsky.app/profile/colormaticstudios.bsky.social"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Bluesky
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<Hero>
|
||||
<span class="text-[200%] font-bold">Links:</span>
|
||||
<div class="mx-auto flex lg:w-[60%]">
|
||||
<Linktree
|
||||
className="flex-1 mx-2"
|
||||
links={[
|
||||
{
|
||||
label: "Mastodon",
|
||||
url: "https://mastodon.social/@colormaticstudios",
|
||||
},
|
||||
{
|
||||
label: "Instagram",
|
||||
url: "https://www.instagram.com/colormaticstudios",
|
||||
},
|
||||
{
|
||||
label: "Youtube",
|
||||
url: "https://www.youtube.com/@colormaticstudios",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Linktree
|
||||
className="flex-1 mx-2"
|
||||
links={[
|
||||
{
|
||||
label: "Colormatic Git",
|
||||
url: "https://git.colormatic.org/ColormaticStudios",
|
||||
},
|
||||
{
|
||||
label: "GitHub",
|
||||
url: "https://github.com/ColormaticStudios",
|
||||
},
|
||||
{
|
||||
label: "Bluesky",
|
||||
url: "https://bsky.app/profile/colormaticstudios.bsky.social",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Hero>
|
||||
</main>
|
||||
|
||||
<spacer></spacer>
|
||||
<Spacer />
|
||||
|
||||
<style lang="scss">
|
||||
@use "../../style/global.scss";
|
||||
|
||||
div.cs-title {
|
||||
background-image: url("/img/colormatic_banner.svg");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
height: 300px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div.cs-title h1 {
|
||||
color: white;
|
||||
background-color: #00000088;
|
||||
padding: 28px 38px;
|
||||
border-radius: 16px;
|
||||
font-size: 300%;
|
||||
box-shadow: 1px 1px 8px #00000033;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
div.project-grid-container {
|
||||
display: flex;
|
||||
width: 80%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
div.project-grid-container {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
div.cs-title {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
div.cs-title h1 {
|
||||
font-size: 200%;
|
||||
}
|
||||
}
|
||||
|
||||
div.project-grid-container div.project-grid-box {
|
||||
flex: 1;
|
||||
margin: 16px;
|
||||
padding: 16px;
|
||||
min-width: 40%;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
div.project-grid-container div.project-grid-box h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.project-grid-container div.project-grid-box h1 a {
|
||||
color: global.$text-color;
|
||||
}
|
||||
|
||||
// Bad code
|
||||
div.project-grid-container div.project-grid-box h1 a:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
div.project-grid-container
|
||||
div.project-grid-box
|
||||
div.project-grid-box-contents {
|
||||
/* Yes, this absurdly long element selector is a joke */
|
||||
display: flex;
|
||||
}
|
||||
|
||||
div.project-grid-container div.project-grid-box img {
|
||||
max-width: 120px;
|
||||
max-height: 150px;
|
||||
margin: 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
div.project-grid-container div.project-grid-box {
|
||||
min-width: 90%;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
div.project-grid-container div.project-grid-box img {
|
||||
max-width: 100px;
|
||||
}
|
||||
img.pixelart {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Hero from "components/hero.svelte";
|
||||
import Linktree from "components/linktree.svelte";
|
||||
import Spacer from "components/spacer.svelte";
|
||||
import { getContext } from "svelte";
|
||||
|
||||
let darkTheme: CallableFunction = getContext("darkTheme");
|
||||
@ -29,26 +32,30 @@
|
||||
<meta property="og:type" content="website" />
|
||||
</svelte:head>
|
||||
|
||||
<main class={darkTheme() ? "dark-theme" : ""}>
|
||||
<main>
|
||||
<img
|
||||
class="banner"
|
||||
class="mx-auto mt-8 mb-8 block w-[95%] rounded-2xl border border-[#00000033]
|
||||
shadow-[1px_1px_8px_#00000033] lg:w-[70%]"
|
||||
src="/img/zakarya-banner.webp"
|
||||
alt="Zakarya Banner"
|
||||
srcset="/img/zakarya-banner.webp 960w, /img/zakarya-banner@2x.webp 1920w"
|
||||
/>
|
||||
<div class="hero panel profile">
|
||||
<div class="nameplate">
|
||||
<Hero className="flex flex-wrap items-center flex-col lg:flex-row">
|
||||
<div class="flex grow lg:flex-col">
|
||||
<img
|
||||
src="/img/zakarya-icon.webp"
|
||||
class="zakarya-icon"
|
||||
class="mx-4 my-2 block h-[38px] rounded-xl lg:mx-auto lg:h-auto lg:w-[100px] lg:rounded-2xl"
|
||||
alt="Zakarya Icon"
|
||||
srcset="/img/zakarya-icon.webp 540w, /img/zakarya-icon@2x.webp 1080w"
|
||||
/>
|
||||
<span class="name-title">Zakarya</span>
|
||||
<span class="text-[200%]">Zakarya</span>
|
||||
</div>
|
||||
|
||||
<div class="bio">
|
||||
<p>
|
||||
<div
|
||||
class="m-3 h-fit rounded-2xl border p-4 text-left text-[120%] lg:max-w-1/2
|
||||
{darkTheme() ? 'border-[#ffffff33]' : 'border-[#00000033]'}"
|
||||
>
|
||||
<p class="mb-4">
|
||||
I am a software and game developer, I run Colormatic and Colormatic
|
||||
Studios, and I primarily study computer science, psychology, and
|
||||
linguistics.
|
||||
@ -60,213 +67,67 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="linktree-container">
|
||||
<ul class="linktree">
|
||||
<li>
|
||||
<a
|
||||
href="https://git.colormatic.org/zakarya"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Colormatic Git
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://mstdn.party/@zakarya"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Mastodon
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://ko-fi.com/zakarya"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Ko-fi
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://www.youtube.com/@czakarya"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Youtube
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/CZakarya"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
<!--<li><a href="https://www.reddit.com/user/CZakarya/" target="_blank" rel="noopener noreferrer">Reddit</a></li>-->
|
||||
</ul>
|
||||
<div class="w-[60%] grow lg:w-[unset]">
|
||||
<Linktree
|
||||
links={[
|
||||
{
|
||||
url: "https://git.colormatic.org/zakarya",
|
||||
label: "Colormatic Git",
|
||||
},
|
||||
{
|
||||
url: "https://mstdn.party/@zakarya",
|
||||
label: "Mastodon",
|
||||
},
|
||||
{
|
||||
url: "https://ko-fi.com/zakarya",
|
||||
label: "Ko-fi",
|
||||
},
|
||||
{
|
||||
url: "https://www.youtube.com/@czakarya",
|
||||
label: "Youtube",
|
||||
},
|
||||
{
|
||||
url: "https://github.com/CZakarya",
|
||||
label: "GitHub",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Hero>
|
||||
|
||||
<div class="hero panel">
|
||||
<h1>Featured Videos:</h1>
|
||||
<ul class="videolist">
|
||||
<li>
|
||||
<Hero>
|
||||
<span class="text-[200%] font-bold">Featured Videos:</span>
|
||||
<ul class="flex list-none flex-wrap justify-center pl-0">
|
||||
<li class="p-2">
|
||||
<a
|
||||
href="https://www.youtube.com/watch?v=FWGCPIEM_-o"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<img
|
||||
class="h-auto w-[250px] rounded-lg"
|
||||
src="https://files.colormatic.org/zakarya/videos/thumbnail/wayforward.png"
|
||||
alt="Video Thumbnail"
|
||||
/>
|
||||
<span class="title">The Way Forward</span>
|
||||
<span class="block p-2 text-[120%]">The Way Forward</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<li class="p-2">
|
||||
<a
|
||||
href="https://www.youtube.com/watch?v=OPD8NqNu0nE"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<img
|
||||
class="h-auto w-[250px] rounded-lg"
|
||||
src="https://files.colormatic.org/zakarya/videos/thumbnail/helloworld.png"
|
||||
alt="Video Thumbnail"
|
||||
/>
|
||||
<span class="title">Hello World</span>
|
||||
<span class="block p-2 text-[120%]">Hello World</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Hero>
|
||||
</main>
|
||||
|
||||
<spacer></spacer>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../../style/global.scss";
|
||||
|
||||
main img.banner {
|
||||
display: block;
|
||||
width: 70%;
|
||||
margin: 32px auto 32px auto;
|
||||
border: solid 1px #00000033;
|
||||
border-radius: 16px;
|
||||
box-shadow: 1px 1px 8px #00000033;
|
||||
}
|
||||
|
||||
main div.profile {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main div.profile div.nameplate {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main div.profile div.nameplate img.zakarya-icon {
|
||||
width: 100px;
|
||||
border-radius: 16px;
|
||||
margin: 8px auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
main div.profile div.nameplate span.name-title {
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
main div.profile div.bio {
|
||||
font-size: 120%;
|
||||
max-width: 50%;
|
||||
padding: 16px;
|
||||
margin: 12px;
|
||||
height: fit-content;
|
||||
text-align: left;
|
||||
/* text-align: justify;
|
||||
text-justify: auto; */
|
||||
border-radius: 16px;
|
||||
border: solid 1px;
|
||||
border-color: #383c3f33; // Same as text color but with alpha
|
||||
}
|
||||
|
||||
main div.profile div.linktree-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
main div.profile div.linktree-container ul.linktree {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
main img.banner {
|
||||
width: 95%;
|
||||
border-radius: 12px;
|
||||
margin: 24px auto;
|
||||
}
|
||||
|
||||
main div.profile div.bio {
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
main div.profile div.linktree-container ul.linktree {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
main div.profile div.nameplate {
|
||||
flex-direction: row;
|
||||
align-items: end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
main div.profile div.nameplate img.zakarya-icon {
|
||||
height: 1.25em;
|
||||
width: auto;
|
||||
font-size: 170%;
|
||||
margin: 0px 12px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
main div.profile div.nameplate span.name-title {
|
||||
font-size: 170%;
|
||||
}
|
||||
}
|
||||
|
||||
main.dark-theme div.profile div.bio {
|
||||
border-color: #ffffff55;
|
||||
}
|
||||
|
||||
ul.videolist {
|
||||
list-style-type: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
ul.videolist li {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
ul.videolist li a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul.videolist li a img {
|
||||
width: 250px;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
ul.videolist li a span {
|
||||
display: block;
|
||||
color: global.$text-color;
|
||||
font-size: 120%;
|
||||
}
|
||||
</style>
|
||||
<Spacer />
|
||||
|
@ -1,2 +0,0 @@
|
||||
$text-color: var(--text-color);
|
||||
$mobile-width: 900px;
|
@ -1,5 +1,3 @@
|
||||
@use "global.scss";
|
||||
|
||||
:root {
|
||||
--text-color: #383c3f;
|
||||
}
|
||||
@ -7,21 +5,17 @@
|
||||
body {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
margin: 0;
|
||||
color: global.$text-color;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: black; // Don't flashbang dark theme users
|
||||
background-color: black; // Don't flashbang dark theme users (CSS loads faster than JS)
|
||||
}
|
||||
:root {
|
||||
--text-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
spacer {
|
||||
display: block;
|
||||
margin-top: 8%;
|
||||
// Javascript does this
|
||||
// :root {
|
||||
// --text-color: white;
|
||||
// }
|
||||
}
|
||||
|
||||
a {
|
||||
@ -44,144 +38,22 @@ a:visited:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
a.btn,
|
||||
button.btn {
|
||||
padding: 8px 18px;
|
||||
border-radius: 6px;
|
||||
font-size: 100px;
|
||||
text-decoration: none;
|
||||
margin: 8px;
|
||||
a.text-color {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
a.btn.lg,
|
||||
button.btn.lg {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
a.btn.blue,
|
||||
button.btn.blue {
|
||||
background-color: #2194ff;
|
||||
border: 1px solid #21afff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.divider {
|
||||
margin: 38px;
|
||||
border-top: 1px solid global.$text-color;
|
||||
}
|
||||
|
||||
div.panel {
|
||||
color: global.$text-color;
|
||||
border: solid 1px;
|
||||
border-color: #00000033;
|
||||
border-radius: 8px;
|
||||
box-shadow: 1px 1px 8px #00000033;
|
||||
background-color: #ffffff22;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
main.dark-theme div.panel {
|
||||
border-color: #ffffff33;
|
||||
}
|
||||
|
||||
div.panel.dark-theme {
|
||||
border-color: #ffffff33;
|
||||
}
|
||||
|
||||
main div.hero {
|
||||
width: 60%;
|
||||
margin: 16px auto;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
spacer {
|
||||
margin-top: 24%;
|
||||
}
|
||||
main div.hero {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
main div.hero h1 a {
|
||||
color: global.$text-color;
|
||||
a.text-color:hover {
|
||||
color: #21afff;
|
||||
}
|
||||
|
||||
p.justify {
|
||||
text-align: justify;
|
||||
text-justify: auto;
|
||||
}
|
||||
|
||||
main div.hero p.justify {
|
||||
width: 60%;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
main div.hero ul {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
main div.hero p.justify {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
ul.linktree {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
padding-left: 8px;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
ul.linktree li {
|
||||
margin: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media screen and (max-width: global.$mobile-width) {
|
||||
ul.linktree {
|
||||
@media (width >= 64rem) {
|
||||
width: 60%;
|
||||
}
|
||||
ul.linktree li {
|
||||
margin: 12px 0;
|
||||
}
|
||||
}
|
||||
|
||||
ul.linktree li a {
|
||||
/* Pill button shape */
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
|
||||
background-color: #4c5053;
|
||||
padding: 8px;
|
||||
border-radius: 50px;
|
||||
box-shadow: 2px 2px 4px #00000066;
|
||||
transition-duration: 0.5s;
|
||||
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
ul.linktree li a:hover {
|
||||
cursor: pointer;
|
||||
background-color: #383c3f;
|
||||
}
|
||||
|
||||
div.double-linktree {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div.double-linktree ul.linktree {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
img.pixelart {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
7
src/style/tailwind.css
Normal file
7
src/style/tailwind.css
Normal file
@ -0,0 +1,7 @@
|
||||
/*/
|
||||
* I have no idea why Tailwind wants a file like this; why can't I just
|
||||
* have an import statement in the +layout.svelte? Web devs seriously
|
||||
* confuse me.
|
||||
/*/
|
||||
|
||||
@import "tailwindcss";
|
@ -6,6 +6,12 @@ const config = {
|
||||
preprocess: vitePreprocess(),
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
blocks: "src/blocks",
|
||||
components: "src/components",
|
||||
script: "src/script",
|
||||
style: "src/style",
|
||||
},
|
||||
},
|
||||
compilerOptions: {
|
||||
runes: true,
|
||||
|
8
tailwind.config.cjs
Normal file
8
tailwind.config.cjs
Normal file
@ -0,0 +1,8 @@
|
||||
/** @type {import("tailwindcss").Config} */
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
plugins: [sveltekit(), tailwindcss()],
|
||||
});
|
||||
|
Reference in New Issue
Block a user