feat(focus-timer): integrate with float window + add pop-out button
Jake's feedback on Phase 1: make the timer pinnable / always-on-top, combined with the existing Now-list pop-out. Two changes: 1. Mount <FocusTimer /> in src/routes/float/+layout@.svelte so the running countdown stays visible in the always-on-top float window alongside the WIP task list. No content change to the float page itself — the timer is a global overlay. 2. Add a pop-out icon to the main-window focus timer that opens the existing /float route via window.open. One click → timer + Now list pinned on top without touching main window focus. Hidden inside the float window itself (detected via URL) so you cannot recursively pop out. Result matches the Todo float-out UX the user already knows: click ExternalLink, you get a small always-on-top window with tasks + a live countdown ring in the top-right.
This commit is contained in:
@@ -15,8 +15,26 @@
|
||||
// follows the sensory-zone theme switcher in Settings.
|
||||
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { X, Plus } from "lucide-svelte";
|
||||
import { X, Plus, ExternalLink } from "lucide-svelte";
|
||||
import { focusTimer } from "$lib/stores/focusTimer.svelte.js";
|
||||
import { hasTauriRuntime } from "$lib/utils/runtime.js";
|
||||
|
||||
// Hide the "pop out" button inside the float window itself — opening
|
||||
// a second float from a float would be silly and would re-mount the
|
||||
// same component. Detect via URL rather than a prop so we do not
|
||||
// have to thread context through every mount site.
|
||||
let isSecondaryWindow = $state(false);
|
||||
if (typeof window !== "undefined") {
|
||||
isSecondaryWindow = window.location.pathname.startsWith("/float")
|
||||
|| window.location.pathname.startsWith("/viewer");
|
||||
}
|
||||
|
||||
function handlePopOut() {
|
||||
// Mirror the button in TasksPage.svelte — opens the always-on-top
|
||||
// Now list + pinned timer in one floating window.
|
||||
if (!hasTauriRuntime()) return;
|
||||
window.open("/float", "_blank", "width=380,height=520");
|
||||
}
|
||||
|
||||
const RING_SIZE = 64;
|
||||
const RING_STROKE = 5;
|
||||
@@ -148,6 +166,16 @@
|
||||
>
|
||||
<Plus size={14} aria-hidden="true" />
|
||||
</button>
|
||||
{#if !isSecondaryWindow}
|
||||
<button
|
||||
class="icon-btn"
|
||||
onclick={handlePopOut}
|
||||
aria-label="Pop out timer + Now list into floating window"
|
||||
title="Pop out (keeps timer + tasks on top)"
|
||||
>
|
||||
<ExternalLink size={14} aria-hidden="true" />
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
class="icon-btn"
|
||||
onclick={handleCancel}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
PREFERENCES_CHANGED_EVENT,
|
||||
} from "$lib/stores/preferences.svelte.js";
|
||||
import Titlebar from "$lib/components/Titlebar.svelte";
|
||||
import FocusTimer from "$lib/components/FocusTimer.svelte";
|
||||
import { loadOsInfo, isLinux } from "$lib/utils/osInfo.js";
|
||||
|
||||
let { children } = $props();
|
||||
@@ -90,3 +91,9 @@
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Focus timer also visible in the always-on-top float window so a
|
||||
running countdown stays with the Now list. The component is a
|
||||
global overlay (position: fixed) so it pins to the top-right of
|
||||
this window independent of the Tasks content below. -->
|
||||
<FocusTimer />
|
||||
|
||||
Reference in New Issue
Block a user