mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-07-24 07:45:57 +02:00
v1.0.0 - Initial release
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
<script lang="ts">
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import { vaultReady, focusMode } from '$lib/stores/app';
|
||||
|
||||
let { onNewNote = () => {} }: {
|
||||
onNewNote?: () => void;
|
||||
} = $props();
|
||||
|
||||
const appWindow = getCurrentWindow();
|
||||
let maximized = $state(false);
|
||||
|
||||
async function checkMaximized() {
|
||||
maximized = await appWindow.isMaximized();
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
checkMaximized();
|
||||
const unlisten = appWindow.onResized(() => checkMaximized());
|
||||
return () => { unlisten.then(fn => fn()); };
|
||||
});
|
||||
|
||||
let lastMouseDown = 0;
|
||||
|
||||
function handleMouseDown(e: MouseEvent) {
|
||||
if (e.button !== 0) return;
|
||||
const target = e.target as HTMLElement;
|
||||
if (target.closest('.titlebar-controls') || target.closest('.titlebar-actions')) return;
|
||||
|
||||
const now = Date.now();
|
||||
if (now - lastMouseDown < 300) {
|
||||
// Double-click detected — maximize/restore
|
||||
appWindow.toggleMaximize();
|
||||
lastMouseDown = 0;
|
||||
return;
|
||||
}
|
||||
lastMouseDown = now;
|
||||
appWindow.startDragging();
|
||||
}
|
||||
|
||||
async function minimize() {
|
||||
await appWindow.minimize();
|
||||
}
|
||||
|
||||
async function toggleMaximize() {
|
||||
await appWindow.toggleMaximize();
|
||||
}
|
||||
|
||||
async function close() {
|
||||
await appWindow.close();
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="titlebar" onmousedown={handleMouseDown}>
|
||||
<div class="titlebar-brand">
|
||||
<svg width="18" height="18" viewBox="0 0 48 48" fill="none">
|
||||
<rect width="48" height="48" rx="12" fill="var(--accent)" />
|
||||
<circle cx="16" cy="16" r="3.5" fill="white" opacity="0.9" />
|
||||
<circle cx="32" cy="16" r="3.5" fill="white" opacity="0.9" />
|
||||
<circle cx="16" cy="32" r="3.5" fill="white" opacity="0.9" />
|
||||
<circle cx="32" cy="32" r="3.5" fill="white" opacity="0.9" />
|
||||
<line x1="19" y1="18" x2="29" y2="30" stroke="white" stroke-width="2" stroke-linecap="round" opacity="0.7" />
|
||||
<line x1="29" y1="18" x2="19" y2="30" stroke="white" stroke-width="2" stroke-linecap="round" opacity="0.7" />
|
||||
</svg>
|
||||
<span class="titlebar-title">HelixNotes</span>
|
||||
</div>
|
||||
<div class="titlebar-actions">
|
||||
<button class="switch-vault-btn" onclick={() => ($vaultReady = false)} title="Switch Vault">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="switch-vault-btn" onclick={() => ($focusMode = true)} title="Focus mode">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="new-note-btn" onclick={onNewNote} title="New Note (Ctrl+N)">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
||||
<path d="M7 1v12M1 7h12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" />
|
||||
</svg>
|
||||
New Note
|
||||
</button>
|
||||
</div>
|
||||
<div class="titlebar-controls">
|
||||
<button class="titlebar-btn" onclick={minimize} title="Minimize">
|
||||
<svg width="10" height="10" viewBox="0 0 10 10">
|
||||
<line x1="1" y1="5" x2="9" y2="5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="titlebar-btn" onclick={toggleMaximize} title={maximized ? 'Restore' : 'Maximize'}>
|
||||
{#if maximized}
|
||||
<svg width="10" height="10" viewBox="0 0 10 10">
|
||||
<rect x="2.5" y="0.5" width="7" height="7" rx="1" fill="none" stroke="currentColor" stroke-width="1.2" />
|
||||
<rect x="0.5" y="2.5" width="7" height="7" rx="1" fill="var(--bg-secondary)" stroke="currentColor" stroke-width="1.2" />
|
||||
</svg>
|
||||
{:else}
|
||||
<svg width="10" height="10" viewBox="0 0 10 10">
|
||||
<rect x="1" y="1" width="8" height="8" rx="1" fill="none" stroke="currentColor" stroke-width="1.2" />
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
<button class="titlebar-btn titlebar-close" onclick={close} title="Close">
|
||||
<svg width="10" height="10" viewBox="0 0 10 10">
|
||||
<line x1="1.5" y1="1.5" x2="8.5" y2="8.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" />
|
||||
<line x1="8.5" y1="1.5" x2="1.5" y2="8.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.titlebar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 34px;
|
||||
background: var(--bg-secondary);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.titlebar-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-left: 14px;
|
||||
pointer-events: none;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.titlebar-title {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.titlebar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-right: 8px;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.switch-vault-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
border-radius: 7px;
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.switch-vault-btn:hover {
|
||||
background: var(--bg-tertiary, var(--bg-hover));
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.new-note-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 12px 4px 10px;
|
||||
border: none;
|
||||
border-radius: 7px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.01em;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
transition: background 0.15s, box-shadow 0.15s, transform 0.1s;
|
||||
}
|
||||
|
||||
.new-note-btn:hover {
|
||||
background: var(--accent-hover);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.new-note-btn:active {
|
||||
transform: scale(0.97);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.titlebar-controls {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.titlebar-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--text-tertiary);
|
||||
cursor: pointer;
|
||||
transition: background 0.1s, color 0.1s;
|
||||
}
|
||||
|
||||
.titlebar-btn:hover {
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.titlebar-close:hover {
|
||||
background: #e81123;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user