Element Bug Fixes
This commit is contained in:
1 parent
1167c686e2
commit
e0bcba74d5
24 files changed
+875
-228
No files matched your search
@@ -0,0 +1,173 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import TerminalTUI from "$lib/components/TerminalTUI.svelte";
|
||||
import { user } from "$lib/config";
|
||||
import { getPageSpeedMultiplier, getPageAutoscroll } from "$lib";
|
||||
import { lines as sourceLines } from "$lib/pages/about";
|
||||
import type { TerminalAPI } from "$lib/components/tui/types";
|
||||
import { onDestroy } from "svelte";
|
||||
|
||||
let lines = $state(sourceLines.map((l) => ({ ...l })));
|
||||
|
||||
const speed = getPageSpeedMultiplier("about");
|
||||
const autoscroll = getPageAutoscroll("about");
|
||||
|
||||
let { data } = $props();
|
||||
const { songs } = data;
|
||||
|
||||
let terminal = $state<TerminalAPI>();
|
||||
let currentSongIndex = $state(0);
|
||||
let isPlaying = $state(false);
|
||||
let progress = $state(0);
|
||||
let timer: ReturnType<typeof setInterval>;
|
||||
|
||||
onMount(() => {
|
||||
// Music player will start when terminal finishes typing
|
||||
});
|
||||
|
||||
function handleTerminalComplete() {
|
||||
if (songs && songs.length > 0) {
|
||||
// Initial update
|
||||
updatePlayerDisplay();
|
||||
togglePlay();
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (timer) clearInterval(timer);
|
||||
});
|
||||
|
||||
function togglePlay() {
|
||||
isPlaying = !isPlaying;
|
||||
if (isPlaying) {
|
||||
timer = setInterval(tick, 500);
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
}
|
||||
updatePlayerDisplay();
|
||||
}
|
||||
|
||||
function tick() {
|
||||
progress += 0.5; // Increment progress
|
||||
if (progress >= 100) {
|
||||
nextSong();
|
||||
} else {
|
||||
updatePlayerDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
function nextSong() {
|
||||
currentSongIndex = (currentSongIndex + 1) % songs.length;
|
||||
progress = 0;
|
||||
updatePlayerDisplay();
|
||||
}
|
||||
|
||||
function prevSong() {
|
||||
currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length;
|
||||
progress = 0;
|
||||
updatePlayerDisplay();
|
||||
}
|
||||
|
||||
function updatePlayerDisplay() {
|
||||
if (!terminal) return;
|
||||
|
||||
const song = songs[currentSongIndex];
|
||||
|
||||
terminal.updateById("music-player", {
|
||||
children: [
|
||||
{
|
||||
type: "output",
|
||||
content: `(&primary)Now Playing:(&) (&text)${song.title}(&)`,
|
||||
},
|
||||
{
|
||||
type: "output",
|
||||
content: `(&primary)Artist:(&) (&text)${song.author}(&)`,
|
||||
},
|
||||
{
|
||||
type: "progress",
|
||||
content: "",
|
||||
progress: progress,
|
||||
progressLabel: `${formatTime(Math.floor((progress / 100) * parseDuration(song.duration || "0:00")))} / ${song.duration}`,
|
||||
inline: false,
|
||||
progressStyle: "text",
|
||||
},
|
||||
{
|
||||
type: "group",
|
||||
content: "",
|
||||
groupDirection: "row",
|
||||
display: "flex",
|
||||
groupExpand: true,
|
||||
children: [
|
||||
{
|
||||
type: "button",
|
||||
content: "⏮",
|
||||
style: "secondary",
|
||||
action: prevSong,
|
||||
textStyle: "center",
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
content: isPlaying ? "⏸" : "▶",
|
||||
style: "primary",
|
||||
action: togglePlay,
|
||||
textStyle: "center",
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
content: "⏭",
|
||||
style: "secondary",
|
||||
action: nextSong,
|
||||
textStyle: "center",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
content: "(&icon, mdi:youtube) Listen on YouTube",
|
||||
style: "primary",
|
||||
href: song.url,
|
||||
external: true,
|
||||
textStyle: "center",
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function parseDuration(duration: string): number {
|
||||
const parts = duration.split(":").map(Number);
|
||||
if (parts.length === 2) return parts[0] * 60 + parts[1];
|
||||
if (parts.length === 3)
|
||||
return parts[0] * 3600 + parts[1] * 60 + parts[2];
|
||||
return 0;
|
||||
}
|
||||
|
||||
function formatTime(seconds: number): string {
|
||||
const mins = Math.floor(seconds / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>About | {user.displayname}</title>
|
||||
<meta name="description" content="About {user.displayname}" />
|
||||
</svelte:head>
|
||||
|
||||
<div class="about-container">
|
||||
<TerminalTUI
|
||||
{lines}
|
||||
title="~/about"
|
||||
interactive={true}
|
||||
{speed}
|
||||
{autoscroll}
|
||||
bind:terminal
|
||||
onComplete={handleTerminalComplete}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.about-container {
|
||||
padding: 2rem 1rem;
|
||||
min-height: calc(100vh - 60px);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user