Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ declare global {
}
interface PageState {
sheet?: string;
clipOverlay?: string;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/ActionSidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
.action-sidebar {
position: absolute;
right: var(--space-lg);
bottom: calc(var(--bottom-nav-height, 64px) + 68px);
bottom: calc(var(--bottom-nav-height, 64px) + 88px);
display: flex;
flex-direction: column;
align-items: center;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/ActivitySheet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { resolve } from '$app/paths';
import { relativeTime } from '$lib/utils';
import { fetchUnreadCount } from '$lib/stores/notifications';
import { viewClipSignal, openCommentsSignal } from '$lib/stores/toasts';
import { clipOverlaySignal, openCommentsSignal } from '$lib/stores/toasts';
import XIcon from 'phosphor-svelte/lib/XIcon';
import BellIcon from 'phosphor-svelte/lib/BellIcon';

Expand Down Expand Up @@ -126,7 +126,7 @@
visible = false;
setTimeout(() => {
ondismiss();
viewClipSignal.set(n.clipId);
clipOverlaySignal.set(n.clipId);
if (n.type !== 'reaction') {
openCommentsSignal.set(n.clipId);
}
Expand Down
48 changes: 24 additions & 24 deletions src/lib/components/AddVideo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@
isPlatformAllowed
} from '$lib/url-validation';
import { addToast } from '$lib/stores/toasts';
import { showShortcutNudge } from '$lib/stores/shortcutNudge';
import { page } from '$app/stores';
import type { GroupMember } from '$lib/types';
import DownloadSimpleIcon from 'phosphor-svelte/lib/DownloadSimpleIcon';
import ClipboardIcon from 'phosphor-svelte/lib/ClipboardIcon';
import XIcon from 'phosphor-svelte/lib/XIcon';
import ArrowRightIcon from 'phosphor-svelte/lib/ArrowRightIcon';
import LightbulbIcon from 'phosphor-svelte/lib/LightbulbIcon';

const {
onsubmitted,
initialUrl,
members = []
}: {
onsubmitted?: (
clip: { id: string; status: string; contentType: string },
caption: string
) => void;
onsubmitted?: (clip: { id: string; status: string; contentType: string }) => void;
initialUrl?: string;
members?: GroupMember[];
} = $props();
Expand Down Expand Up @@ -132,7 +131,7 @@
contentType: data.clip.contentType,
autoDismiss: 0
});
onsubmitted?.(data.clip, '');
onsubmitted?.(data.clip);
} catch {
error = 'Something went wrong';
} finally {
Expand Down Expand Up @@ -229,6 +228,14 @@
<p class="platform-blocked">{platformLabel(url.trim())} links aren't allowed in this group</p>
{/if}
<InlineError message={error} />

{#if $showShortcutNudge}
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
<a href="/share/setup" class="share-hint">
<LightbulbIcon size={14} />
Share clips faster from other apps
</a>
{/if}
</form>
{/if}

Expand All @@ -240,7 +247,6 @@
gap: var(--space-md);
padding: var(--space-sm) var(--space-lg) var(--space-lg);
}

.clipboard-suggestion {
display: flex;
align-items: center;
Expand Down Expand Up @@ -326,8 +332,6 @@
transform: translateY(0);
}
}

/* iMessage-style compose fields */
.compose-fields {
width: 100%;
background: var(--bg-elevated);
Expand All @@ -338,54 +342,45 @@
border-color 0.2s ease,
box-shadow 0.2s ease;
}

.compose-fields:focus-within {
border-color: var(--accent-primary);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-primary) 15%, transparent);
}

.field-row {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-xs) var(--space-md);
}

.message-row {
align-items: flex-start;
padding-top: var(--space-sm);
padding-bottom: var(--space-sm);
}

.field-label {
font-size: 0.8125rem;
font-weight: 600;
color: var(--text-muted);
flex-shrink: 0;
min-width: 56px;
}

.message-row .field-label {
padding-top: var(--space-xs);
}

.field-divider {
height: 1px;
background: var(--border);
margin: 0 var(--space-md);
}

.field-input-wrap {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
}

.field-input-wrap.has-error input {
color: var(--error);
}

.field-input-wrap input {
flex: 1;
padding: 10px 0;
Expand Down Expand Up @@ -439,16 +434,13 @@
width: 18px;
height: 18px;
}

.submit-btn:active {
transform: scale(0.92);
}

.submit-btn:disabled {
opacity: 0.35;
cursor: not-allowed;
}

.spinner {
width: 16px;
height: 16px;
Expand All @@ -457,13 +449,11 @@
border-radius: var(--radius-full);
animation: spin 0.6s linear infinite;
}

@keyframes spin {
to {
transform: rotate(360deg);
}
}

.platform-blocked {
margin: 0;
font-size: 0.8125rem;
Expand All @@ -476,15 +466,13 @@
text-align: center;
padding: var(--space-2xl) var(--space-lg);
}

.no-provider-state :global(.no-provider-icon) {
width: 40px;
height: 40px;
color: var(--text-muted);
opacity: 0.4;
margin-bottom: var(--space-md);
}

.no-provider-title {
font-family: var(--font-display);
font-size: 1rem;
Expand All @@ -497,4 +485,16 @@
color: var(--text-muted);
margin: 0;
}
.share-hint {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-size: 0.75rem;
color: var(--text-muted);
text-decoration: underline;
text-underline-offset: 2px;
}
.share-hint :global(svg) {
flex-shrink: 0;
}
</style>
50 changes: 3 additions & 47 deletions src/lib/components/AddVideoModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import AddVideo from './AddVideo.svelte';
import UploadStatus from './UploadStatus.svelte';
import BaseSheet from './BaseSheet.svelte';
import { addToast, toast, toasts } from '$lib/stores/toasts';
import { clipReadySignal, viewClipSignal } from '$lib/stores/toasts';
import { addToast, toasts, clipReadySignal, clipOverlaySignal } from '$lib/stores/toasts';
import { dismissShortcutNudge } from '$lib/stores/shortcutNudge';
import { groupMembers } from '$lib/stores/members';

Expand All @@ -14,13 +13,9 @@
let phase = $state<'form' | 'uploading' | 'done' | 'failed'>('form');
let clipId = $state('');
let clipContentType = $state('');
let caption = $state('');
let captionDirty = $state(false);
let serverTitle = $state<string | null>(null);
let serverArtist = $state<string | null>(null);
let serverAlbumArt = $state<string | null>(null);
let pollTimer: ReturnType<typeof setInterval> | null = null;
let savingCaption = $state(false);
let addVideoRef = $state<ReturnType<typeof AddVideo> | null>(null);
let sheetRef = $state<ReturnType<typeof BaseSheet> | null>(null);

Expand All @@ -45,13 +40,9 @@
timers.forEach(clearTimeout);
});

function handleSubmitted(
clip: { id: string; status: string; contentType: string },
submittedCaption: string
) {
function handleSubmitted(clip: { id: string; status: string; contentType: string }) {
clipId = clip.id;
clipContentType = clip.contentType;
caption = submittedCaption;
// Remove the processing toast AddVideo created — UploadStatus screen takes over
toasts.update((t) => t.filter((item) => item.clipId !== clip.id));
phase = 'uploading';
Expand All @@ -65,10 +56,6 @@
if (!res.ok) return;
const data = await res.json();

// Update metadata from server (e.g. music title/artist from Odesli)
if (data.title && !captionDirty) {
serverTitle = data.title;
}
if (data.artist) serverArtist = data.artist;
if (data.albumArt) serverAlbumArt = data.albumArt;

Expand Down Expand Up @@ -101,24 +88,6 @@
}
}

async function saveCaption() {
if (!captionDirty || !caption.trim()) return;
savingCaption = true;
try {
const res = await fetch(`/api/clips/${clipId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: caption.trim() })
});
if (!res.ok) {
toast.error('Failed to save caption');
}
} catch {
toast.error('Failed to save caption');
}
savingCaption = false;
}

function dismiss() {
// If still uploading, push a background toast
if (phase === 'uploading') {
Expand All @@ -134,25 +103,15 @@
}

async function handleSaveAndView() {
if (captionDirty && caption.trim()) {
await saveCaption();
}
clipReadySignal.set(clipId);
viewClipSignal.set(clipId);
clipOverlaySignal.set(clipId);
sheetRef?.dismiss();
}

function handleCaptionInput(e: Event) {
caption = (e.target as HTMLInputElement).value;
captionDirty = true;
}

function handleDismissNudge() {
dismissShortcutNudge();
sheetRef?.dismiss();
}

const displayTitle = $derived(captionDirty ? caption : serverTitle || caption || '');
</script>

<div class="add-video-wrapper" class:fullscreen={phase !== 'form'}>
Expand All @@ -178,14 +137,11 @@
<UploadStatus
{phase}
{clipContentType}
{displayTitle}
{serverArtist}
{serverAlbumArt}
{savingCaption}
ondismiss={dismiss}
onretry={handleRetry}
onsaveandview={handleSaveAndView}
oncaptioninput={handleCaptionInput}
ondismissnudge={handleDismissNudge}
/>
{/if}
Expand Down
Loading
Loading