Chore update 010 #4

Merged
iamdoubz merged 2 commits from chore_update_010 into main 2026-07-08 20:58:14 -05:00
3 changed files with 76 additions and 36 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

+67 -36
View File
@@ -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 (
<div className="relative h-16 w-16 shrink-0">
<img
src={artworkUrl}
alt=""
className="h-full w-full rounded-lg object-cover"
loading="lazy"
/>
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 */}
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setPlaying(!playing);
setOpen(true);
}}
className={`absolute inset-0 flex items-center justify-center rounded-lg transition-opacity ${
playing
? "bg-black/40 opacity-100"
: "bg-black/40 opacity-0 hover:opacity-100"
}`}
aria-label={playing ? "Stop" : "Play"}
className="group/sc relative h-16 w-16 shrink-0"
aria-label="Play track"
>
{playing ? (
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
<rect x="6" y="4" width="4" height="16" rx="1" />
<rect x="14" y="4" width="4" height="16" rx="1" />
</svg>
) : (
<img
src={artworkUrl}
alt=""
className="h-full w-full rounded-lg object-cover"
loading="lazy"
/>
<div className="absolute inset-0 flex items-center justify-center rounded-lg bg-black/40 opacity-0 transition-opacity group-hover/sc:opacity-100">
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
<path d="M8 5v14l11-7z" />
</svg>
)}
</div>
</button>
{/* Hidden audio widget */}
{playing && (
<iframe
src={widgetSrc}
width="0"
height="0"
allow="autoplay"
className="absolute opacity-0 pointer-events-none"
title="SoundCloud player"
/>
{/* Modal — portaled to body so it's above everything */}
{open && createPortal(
<div
className="fixed inset-0 flex items-center justify-center"
style={{ zIndex: 9999 }}
onClick={() => setOpen(false)}
>
{/* Backdrop */}
<div className="absolute inset-0 bg-black/80 backdrop-blur-sm" />
{/* Player */}
<div
className="relative w-full max-w-2xl mx-4 rounded-xl overflow-hidden shadow-[0_0_60px_rgba(0,0,0,0.8)]"
onClick={(e) => e.stopPropagation()}
>
<iframe
src={widgetSrc}
width="100%"
height="166"
allow="autoplay"
className="block"
title="SoundCloud player"
/>
</div>
{/* Close button */}
<button
onClick={() => setOpen(false)}
className="absolute top-6 right-6 flex h-10 w-10 items-center justify-center rounded-full bg-white/10 text-white transition-colors hover:bg-white/20"
aria-label="Close player"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<path d="M18 6L6 18M6 6l12 12" />
</svg>
</button>
</div>,
document.body,
)}
</div>
</>
);
}
+9
View File
@@ -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: [