add theme toggle

This commit is contained in:
liyunze 2026-09-03 16:01:05 +08:00
parent 1a3249a9fb
commit a854b4df1b
5 changed files with 71 additions and 10 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -4,6 +4,7 @@ import { Image } from "astro:assets";
interface Props { interface Props {
position?: "left" | "right"; position?: "left" | "right";
image?: ImageMetadata; image?: ImageMetadata;
image_light?: ImageMetadata;
alt?: string; alt?: string;
href: string; href: string;
title: string; title: string;
@ -14,6 +15,7 @@ interface Props {
const { const {
image, image,
image_light,
alt, alt,
href, href,
title, title,
@ -40,18 +42,42 @@ const leftProject = position == "left";
<Image <Image
src={image} src={image}
alt={alt} alt={alt}
class="background-img absolute top-1/2 left-1/2 aspect-video max-w-full rounded-xl border-2 border-solid border-gray-800 opacity-40" class="project-image-dark background-img absolute top-1/2 left-1/2 aspect-video max-w-full rounded-xl border-2 border-solid border-gray-800 opacity-40"
class:list={leftProject ? "left" : "right"} class:list={[
leftProject ? "left" : "right",
{ "has-light-image": Boolean(image_light) },
]}
width={700} width={700}
/> />
<Image <Image
src={image} src={image}
alt={alt} alt={alt}
width={700} width={700}
class="frontfacing-img absolute top-1/2 left-1/2 aspect-video max-w-full rounded-xl border-2 border-solid border-gray-800 opacity-100" class="project-image-dark frontfacing-img absolute top-1/2 left-1/2 aspect-video max-w-full rounded-xl border-2 border-solid border-gray-800 opacity-100"
class:list={[
leftProject ? "left" : "right",
{ "has-light-image": Boolean(image_light) },
]}
/>
{image_light && (
<>
<Image
src={image_light}
alt={alt}
class="project-image-light background-img absolute top-1/2 left-1/2 hidden aspect-video max-w-full rounded-xl border-2 border-solid border-gray-300 opacity-40"
class:list={leftProject ? "left" : "right"}
width={700}
/>
<Image
src={image_light}
alt={alt}
width={700}
class="project-image-light frontfacing-img absolute top-1/2 left-1/2 hidden aspect-video max-w-full rounded-xl border-2 border-solid border-gray-300 opacity-100"
class:list={leftProject ? "left" : "right"} class:list={leftProject ? "left" : "right"}
/> />
</> </>
)}
</>
) )
} }
@ -106,6 +132,14 @@ const leftProject = position == "left";
</div> </div>
<style> <style>
:global(html[data-theme="light"]) .project-image-dark.has-light-image {
display: none;
}
:global(html[data-theme="light"]) .project-image-light {
display: block;
}
.image-container img { .image-container img {
transition: transform 0.5s ease-in-out; transition: transform 0.5s ease-in-out;
} }

View file

@ -1,8 +1,11 @@
--- ---
import TaskWidget from "./TaskWidget.svelte"; import TaskWidget from "./TaskWidget.svelte";
import CoworkingGuide from "../images/projects/coworking-guide.webp"; import CoworkingGuide from "../images/projects/coworking-guide.webp";
import CoworkingGuideLight from "../images/projects/coworking-guide-light.webp";
import PortfolioRoastBot from "../images/projects/portfolio-roast-bot.webp"; import PortfolioRoastBot from "../images/projects/portfolio-roast-bot.webp";
import PortfolioRoastBotLight from "../images/projects/lightmode-portfolioroastbot.webp";
import DsecNotebook from "../images/projects/dsec-notebook.webp"; import DsecNotebook from "../images/projects/dsec-notebook.webp";
import DsecNotebookLight from "../images/projects/dsec-notebook-light.webp";
import Project from "./Project.astro"; import Project from "./Project.astro";
--- ---
@ -14,6 +17,7 @@ import Project from "./Project.astro";
<Project <Project
position="left" position="left"
image={CoworkingGuide} image={CoworkingGuide}
image_light={CoworkingGuideLight}
alt="coworking guide" alt="coworking guide"
href="https://coworking-guide.vercel.app/" href="https://coworking-guide.vercel.app/"
title="Coworking Guide" title="Coworking Guide"
@ -25,6 +29,7 @@ import Project from "./Project.astro";
<Project <Project
position="right" position="right"
image={DsecNotebook} image={DsecNotebook}
image_light={DsecNotebookLight}
alt="DSEC Notebook" alt="DSEC Notebook"
href="https://notebook.dsec.club/" href="https://notebook.dsec.club/"
title="DSEC Notebook" title="DSEC Notebook"
@ -36,6 +41,7 @@ import Project from "./Project.astro";
<Project <Project
position="left" position="left"
image={PortfolioRoastBot} image={PortfolioRoastBot}
image_light={PortfolioRoastBotLight}
alt="Portfolio Roast Bot" alt="Portfolio Roast Bot"
href="https://codeberg.org/RythonDev/portfolio-roast-bot" href="https://codeberg.org/RythonDev/portfolio-roast-bot"
label="View Repository" label="View Repository"

View file

@ -145,7 +145,7 @@
<!-- task bot --> <!-- task bot -->
<div class="task-widget absolute flex h-full min-h-[50vh] w-full flex-col"> <div class="task-widget absolute flex h-full min-h-[50vh] w-full flex-col">
<div <div
class="flex w-full flex-row items-center justify-between class="task-widget-header flex w-full flex-row items-center justify-between
rounded-md rounded-md
border-3 border-solid border-3 border-solid
border-gray-600 bg-black border-gray-600 bg-black
@ -161,7 +161,7 @@
<div class="scroll-element primary absolute w-full px-1"> <div class="scroll-element primary absolute w-full px-1">
{#each streamers as { streamer, tasks }} {#each streamers as { streamer, tasks }}
<div <div
class="my-2 w-full overflow-hidden rounded-md bg-[#404040] px-5 py-1 class="task-widget-item my-2 w-full overflow-hidden rounded-md bg-[#404040] px-5 py-1
text-sm overflow-ellipsis whitespace-nowrap text-white lg:text-base" text-sm overflow-ellipsis whitespace-nowrap text-white lg:text-base"
> >
{streamer} : {streamer} :
@ -169,8 +169,8 @@
{#each tasks as task} {#each tasks as task}
<li <li
class={task.completed class={task.completed
? "text-gray-400 line-through" ? "task-completed text-gray-400 line-through"
: "text-white"} : "task-incomplete text-white"}
> >
{task.name} {task.name}
</li> </li>
@ -182,14 +182,16 @@
<div class="scroll-element secondary absolute w-full px-1"> <div class="scroll-element secondary absolute w-full px-1">
{#each streamers as { streamer, tasks }} {#each streamers as { streamer, tasks }}
<div <div
class="my-2 w-full overflow-hidden rounded-md bg-[#404040] px-5 py-1 class="task-widget-item my-2 w-full overflow-hidden rounded-md bg-[#404040] px-5 py-1
text-sm overflow-ellipsis whitespace-nowrap text-white lg:text-base" text-sm overflow-ellipsis whitespace-nowrap text-white lg:text-base"
> >
{streamer} : {streamer} :
<ol class="list-inside list-decimal"> <ol class="list-inside list-decimal">
{#each tasks as task} {#each tasks as task}
<li <li
class={task.completed ? "line-through" : ""} class={task.completed
? "task-completed line-through"
: "task-incomplete"}
> >
{task.name} {task.name}
</li> </li>
@ -203,6 +205,25 @@
</div> </div>
<style> <style>
:global(html[data-theme="light"]) .task-widget-header {
border-color: #cbd5e1;
background-color: #f8fafc;
color: #0f172a;
}
:global(html[data-theme="light"]) .task-widget-item {
background-color: #e2e8f0;
color: #0f172a;
}
:global(html[data-theme="light"]) .task-incomplete {
color: #0f172a;
}
:global(html[data-theme="light"]) .task-completed {
color: #64748b;
}
.background-widget.left { .background-widget.left {
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }