Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/lib/components/SafariAnnotationWarning.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script lang="ts">
import { dismissSafariWarning, shouldShowSafariWarning } from '$lib/scripts/safariUtils';

let visible = $state(shouldShowSafariWarning());

function dismiss() {
dismissSafariWarning();
visible = false;
}
</script>

{#if visible}
<div
class="flex items-start gap-3 bg-amber-50 border border-amber-300 text-amber-900 rounded-lg px-4 py-3 mx-2.5 mt-2.5 text-sm"
>
<svg
class="shrink-0 mt-0.5 w-5 h-5 text-amber-500"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z"
clip-rule="evenodd"
/>
</svg>
<div class="flex-1">
<p class="font-semibold">Annotations may be deleted by Safari</p>
<p class="mt-0.5">
Safari can delete your bookmarks, highlights, and notes after 1–2 weeks of
inactivity. To keep them permanently, add this app to your Home Screen.
</p>
</div>
<button
onclick={dismiss}
class="shrink-0 text-amber-500 hover:text-amber-700"
aria-label="Dismiss"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
{/if}
48 changes: 48 additions & 0 deletions src/lib/scripts/safariUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const DISMISSED_KEY = 'safari_annotation_warning_dismissed';
const DISMISS_DURATION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days

function isSafariWithoutStandalone(): boolean {
if (typeof window === 'undefined') {
return false;
}
const ua = navigator.userAgent;
const isSafari = /Safari/.test(ua) && !/Chrome|CriOS|FxiOS|EdgiOS/.test(ua);
const isStandalone = (navigator as Navigator & { standalone?: boolean }).standalone === true;
return isSafari && !isStandalone;
}

export function shouldShowSafariWarning(): boolean {
if (typeof window === 'undefined') {
return false;
}
// Debug override: because the app uses hash routing, append ?debug_safari=true
// inside the hash, e.g. /#/bookmarks?debug_safari=true
const hashQuery = window.location.hash.split('?')[1] ?? '';
if (new URLSearchParams(hashQuery).get('debug_safari') === 'true') {
return true;
}
if (!isSafariWithoutStandalone()) {
return false;
}
try {
const dismissed = localStorage.getItem(DISMISSED_KEY);
if (!dismissed) {
return true;
}
const dismissedAt = parseInt(dismissed, 10);
if (isNaN(dismissedAt)) {
return true;
}
return Date.now() - dismissedAt > DISMISS_DURATION_MS;
} catch {
return true;
}
}

export function dismissSafariWarning(): void {
try {
localStorage.setItem(DISMISSED_KEY, Date.now().toString());
} catch {
// If storage is unavailable, silently ignore — the warning will reappear next visit
}
}
2 changes: 2 additions & 0 deletions src/routes/bookmarks/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { resolve } from '$app/paths';
import IconCard from '$lib/components/IconCard.svelte';
import Navbar from '$lib/components/Navbar.svelte';
import SafariAnnotationWarning from '$lib/components/SafariAnnotationWarning.svelte';
import SortMenu from '$lib/components/SortMenu.svelte';
import { shareAnnotation, shareAnnotations } from '$lib/data/annotation-share';
import { SORT_DATE, SORT_REFERENCE, toSorted } from '$lib/data/annotation-sort';
Expand Down Expand Up @@ -82,6 +83,7 @@
class="overflow-y-auto p-2.5 max-w-screen-md mx-auto w-full"
style:font-size="{$bodyFontSize}px"
>
<SafariAnnotationWarning />
{#if data.bookmarks.length === 0}
<div class="annotation-message-none">{$t['Annotation_Bookmarks_None']}</div>
<div class="annotation-message-none-info">{$t['Annotation_Bookmarks_None_Info']}</div>
Expand Down
2 changes: 2 additions & 0 deletions src/routes/highlights/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { resolve } from '$app/paths';
import IconCard from '$lib/components/IconCard.svelte';
import Navbar from '$lib/components/Navbar.svelte';
import SafariAnnotationWarning from '$lib/components/SafariAnnotationWarning.svelte';
import SortMenu from '$lib/components/SortMenu.svelte';
import { shareAnnotation, shareAnnotations } from '$lib/data/annotation-share';
import { SORT_COLOR, SORT_DATE, SORT_REFERENCE, toSorted } from '$lib/data/annotation-sort';
Expand Down Expand Up @@ -88,6 +89,7 @@
class="overflow-y-auto p-2.5 max-w-screen-md mx-auto w-full"
style:font-size="{$bodyFontSize}px"
>
<SafariAnnotationWarning />
{#if data.highlights.length === 0}
<div class="annotation-message-none">{$t['Annotation_Highlights_None']}</div>
<div class="annotation-message-none-info">{$t['Annotation_Highlights_None_Info']}</div>
Expand Down
2 changes: 2 additions & 0 deletions src/routes/notes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { resolve } from '$app/paths';
import IconCard from '$lib/components/IconCard.svelte';
import Navbar from '$lib/components/Navbar.svelte';
import SafariAnnotationWarning from '$lib/components/SafariAnnotationWarning.svelte';
import SortMenu from '$lib/components/SortMenu.svelte';
import { shareAnnotation, shareAnnotations } from '$lib/data/annotation-share';
import { SORT_DATE, SORT_REFERENCE, toSorted } from '$lib/data/annotation-sort';
Expand Down Expand Up @@ -81,6 +82,7 @@
class="overflow-y-auto p-2.5 max-w-screen-md mx-auto w-full"
style:font-size="{$bodyFontSize}px"
>
<SafariAnnotationWarning />
{#if data.notes.length === 0}
<div class="annotation-message-none">{$t['Annotation_Notes_None']}</div>
<div class="annotation-message-none-info">{$t['Annotation_Notes_None_Info']}</div>
Expand Down
Loading