diff --git a/public/images/projects/whispassist.png b/public/images/projects/whispassist.png
new file mode 100644
index 0000000..d6e827b
Binary files /dev/null and b/public/images/projects/whispassist.png differ
diff --git a/src/components/ui/SoundCloudPlayer.tsx b/src/components/ui/SoundCloudPlayer.tsx
index c65be51..c679583 100644
--- a/src/components/ui/SoundCloudPlayer.tsx
+++ b/src/components/ui/SoundCloudPlayer.tsx
@@ -1,6 +1,7 @@
"use client";
-import { useState } from "react";
+import { useState, useEffect } from "react";
+import { createPortal } from "react-dom";
interface SoundCloudPlayerProps {
trackUrl: string;
@@ -8,56 +9,86 @@ interface SoundCloudPlayerProps {
}
export function SoundCloudPlayer({ trackUrl, artworkUrl }: SoundCloudPlayerProps) {
- const [playing, setPlaying] = useState(false);
+ const [open, setOpen] = useState(false);
const widgetSrc = `https://w.soundcloud.com/player/?url=${encodeURIComponent(trackUrl)}&auto_play=true&hide_related=true&show_comments=false&show_user=false&show_reposts=false&show_teaser=false&visual=false`;
- return (
-
-

+ useEffect(() => {
+ if (!open) return;
+ function onKey(e: KeyboardEvent) {
+ if (e.key === "Escape") setOpen(false);
+ }
+ document.addEventListener("keydown", onKey);
+ document.body.style.overflow = "hidden";
+ return () => {
+ document.removeEventListener("keydown", onKey);
+ document.body.style.overflow = "";
+ };
+ }, [open]);
- {/* Play/pause overlay */}
+ return (
+ <>
+ {/* Artwork with play button */}
- {/* Hidden audio widget */}
- {playing && (
-
+ {/* Modal — portaled to body so it's above everything */}
+ {open && createPortal(
+
setOpen(false)}
+ >
+ {/* Backdrop */}
+
+
+ {/* Player */}
+
e.stopPropagation()}
+ >
+
+
+
+ {/* Close button */}
+
+
,
+ document.body,
)}
-
+ >
);
}
diff --git a/src/lib/config.ts b/src/lib/config.ts
index b69bc85..a98897c 100644
--- a/src/lib/config.ts
+++ b/src/lib/config.ts
@@ -74,6 +74,15 @@ export const siteConfig = {
url: "",
github: "https://github.com/iamdoubz/ha-zmodo",
},
+ {
+ title: "WhispAssist",
+ description:
+ "Windows-native meeting assistant that captures system audio, transcribes it locally with Whisper-class models (NPU/GPU/CPU accelerated), performs speaker diarization, and generates Markdown notes — nothing leaves the device unless configured.",
+ tags: ["Rust", "Tauri", "Svelte", "Whisper", "ONNX"],
+ image: "/images/projects/whispassist.png",
+ url: "",
+ github: "https://git.dou.bet/iamdoubz/WhispAssist",
+ },
],
techStack: [