[READ-ONLY] Mirror of https://github.com/probablykasper/ferrum. Music library app for Mac, Linux and Windows ferrum.kasper.space
electron linux macos music music-library music-player napi windows
0

Configure Feed

Select the types of activity you want to include in your feed.

Show player during mousemove

Kasper (Oct 2, 2025, 11:46 PM +0200) f445191a d42b4f6f

+50 -15
+1 -1
src/App.svelte
··· 285 285 <Queue /> 286 286 {/if} 287 287 </div> 288 - <Player on_show_visualizer={toggle_visualizer} /> 288 + <Player on_toggle_visualizer={toggle_visualizer} /> 289 289 {#if droppable} 290 290 <!-- if the overlay is always visible, it's not possible to scroll while dragging tracks --> 291 291 <div class="drag-overlay" transition:fade={{ duration: 100 }}>
+3 -3
src/components/Player.svelte
··· 21 21 import { ipc_renderer } from '$lib/window' 22 22 import { tracks_page_item_ids } from './TrackList.svelte' 23 23 24 - export let on_show_visualizer: () => void 24 + export let on_toggle_visualizer: () => void 25 25 26 26 async function playing_context_menu() { 27 27 const playing = queue.getCurrent() ··· 234 234 <button 235 235 type="button" 236 236 class="mr-2" 237 - aria-label="Show visualizer" 237 + aria-label="Toggle visualizer" 238 238 tabindex="-1" 239 239 on:click={() => { 240 - on_show_visualizer() 240 + on_toggle_visualizer() 241 241 }} 242 242 > 243 243 <div class="parent-active-zoom">
+1 -1
src/lib/helpers.ts
··· 35 35 } 36 36 const is_mac = navigator.userAgent.indexOf('Mac') !== -1 37 37 38 - function check_modifiers(e: KeyboardEvent | MouseEvent, options: ShortcutOptions) { 38 + export function check_modifiers(e: KeyboardEvent | MouseEvent, options: ShortcutOptions) { 39 39 const target = { 40 40 shift: options.shift || false, 41 41 alt: options.alt || false,
+45 -10
src/lib/visualizer/Visualizer.svelte
··· 3 3 import { ShaderToyLite } from './ShaderToyLite.js' 4 4 import { onMount } from 'svelte' 5 5 import { audioContext, mediaElementSource } from '$lib/player' 6 + import Player from '$components/Player.svelte' 7 + import { fly } from 'svelte/transition' 8 + import { check_modifiers } from '$lib/helpers' 6 9 7 - export let on_close: () => void 10 + let { on_close }: { on_close: () => void } = $props() 8 11 9 12 let canvas: HTMLCanvasElement | undefined 10 13 const canvas_id = 'visualizer' ··· 57 60 toy.setBufferA({ source: a }) 58 61 toy.setImage({ source: image, iChannel0: 'A' }) 59 62 toy.play() 60 - console.log('start') 61 63 const visualizer = start_visualizer(audioContext, mediaElementSource, (info) => { 62 64 toy?.setStream(info.stream) 63 65 toy?.setVolume(info.volume) ··· 67 69 visualizer.destroy() 68 70 } 69 71 }) 72 + 73 + let show_player = $state(false) 74 + let hide_player_timeout: ReturnType<typeof setTimeout> | undefined 75 + function show_player_temporarily() { 76 + show_player = true 77 + clearTimeout(hide_player_timeout) 78 + hide_player_timeout = setTimeout(() => { 79 + show_player = false 80 + }, 1000) 81 + } 70 82 </script> 71 83 72 84 <svelte:window ··· 80 92 /> 81 93 82 94 <dialog 95 + class="overflow-hidden" 83 96 {@attach (e) => { 84 97 e.showModal() 85 98 }} 86 - on:close={() => { 99 + onclose={() => { 87 100 on_close() 88 101 }} 102 + onkeydown={(e) => { 103 + if (check_modifiers(e, {})) { 104 + show_player_temporarily() 105 + } 106 + }} 89 107 > 90 - <canvas 91 - bind:this={canvas} 92 - class="fixed h-screen w-screen" 93 - id={canvas_id} 94 - width={window.innerWidth} 95 - height={window.innerHeight} 96 - ></canvas> 108 + <div class="h-screen w-screen"> 109 + <canvas 110 + bind:this={canvas} 111 + class="fixed inset-0" 112 + id={canvas_id} 113 + width={window.innerWidth} 114 + height={window.innerHeight} 115 + onmousemove={show_player_temporarily} 116 + ></canvas> 117 + {#if show_player} 118 + <!-- svelte-ignore a11y_no_static_element_interactions --> 119 + <div 120 + class="fixed bottom-0 flex w-full flex-col justify-end" 121 + transition:fly={{ y: '100%', duration: 500 }} 122 + onmouseenter={() => { 123 + show_player = true 124 + clearTimeout(hide_player_timeout) 125 + }} 126 + onmouseleave={show_player_temporarily} 127 + > 128 + <Player on_toggle_visualizer={on_close} /> 129 + </div> 130 + {/if} 131 + </div> 97 132 </dialog>