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
9 changes: 8 additions & 1 deletion js/app/packages/app/component/Launcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,14 @@ export const Launcher = (props: LauncherProps) => {
</Dialog.Overlay>

<Dialog.Content>
<div class="fixed inset-0 z-modal w-screen h-screen flex items-center justify-center">
<div
class="fixed inset-0 z-modal w-screen h-screen flex items-center justify-center"
onClick={(e) => {
if (e.target === e.currentTarget) {
props.onOpenChange(false);
}
}}
>
<LauncherInner
onClose={(shouldReturnFocus) =>
props.onOpenChange(false, shouldReturnFocus)
Expand Down
1 change: 1 addition & 0 deletions js/app/packages/app/component/UnifiedListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ export function UnifiedListView(props: UnifiedListViewProps) {
return;
}

if (isTouchDevice) return;
if (!firstEntity) return;

setSelectedEntity(firstEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ function SplitPreviewToggle() {
function SplitControlButtons() {
return (
<div class="flex flex-row items-center px-2 h-full shrink-0">
<SplitCloseButton />
<div class="ios:hidden">
<SplitCloseButton />
</div>
<SplitBackButton />
<SplitForwardButton />
</div>
Expand Down Expand Up @@ -152,12 +154,12 @@ export function SplitHeader(props: { ref: Setter<HTMLDivElement | null> }) {
<div class="h-full grow-1" />

<div
class="min-w-4 h-full shrink-0"
class="min-w-4 h-full shrink-0 ios:hidden"
ref={(ref) => {
ctx.layoutRefs.headerRight = ref;
}}
/>
<div class="z-2 relative flex items-center bg-panel pr-2 h-full">
<div class="z-2 relative flex items-center bg-panel pr-2 h-full ios:hidden">
<EntityNavigationIndicator />
<SplitPreviewToggle />
<SplitSpotlightButton />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { EntityIcon } from '@core/component/EntityIcon';
import type { Property } from '@core/component/Properties/types';
import { LabelAndHotKey, Tooltip } from '@core/component/Tooltip';
import { TOKENS } from '@core/hotkey/tokens';
import { isTouchDevice } from '@core/mobile/isTouchDevice';
import { matches } from '@core/util/match';
import CheckIcon from '@icon/regular/check.svg';
import { tryToTypedNotification } from '@notifications';
Expand Down Expand Up @@ -505,16 +506,16 @@ export function EntityWithEverything(
const isSearch = () => isSearchEntity(props.entity);

return (
<div class="flex gap-1 items-center text-sm min-w-0 w-full truncate overflow-hidden @max-sm/split:flex-col @max-sm/split:items-start @max-sm/split:gap-1 @max-sm/split:truncate-none">
<div class="flex gap-1 items-center text-sm min-w-0 w-full truncate overflow-hidden @max-md/split:flex-col @max-md/split:items-start @max-md/split:gap-1 @max-md/split:truncate-none">
{/* sometimes senderName and senderEmail are the same */}
<div
class="flex gap-2 items-center font-semibold shrink-0 @max-sm/split:w-full @max-sm/split:truncate"
class="flex gap-2 items-center font-semibold shrink-0 @max-md/split:w-full @max-md/split:truncate"
classList={{
'w-[20cqw]': !isSearch(),
}}
>
{/* Icon inline with sender in narrow mode */}
<div class="hidden @max-sm/split:flex size-[1em] shrink-0 items-center justify-center relative group/icon-checkbox">
<div class="hidden @max-md/split:flex size-[1em] shrink-0 items-center justify-center relative group/icon-checkbox">
{/* Checkbox for narrow mode - shown on hover or when checked */}
<button
type="button"
Expand Down Expand Up @@ -553,7 +554,7 @@ export function EntityWithEverything(
</div>
</div>
{/* Sender Name */}
<div class="truncate @max-sm/split:min-w-0">
<div class="truncate @max-md/split:min-w-0">
{displayedNames() ??
props.entity.senderName ??
props.entity.senderEmail?.split('@')[0]}
Expand All @@ -571,17 +572,17 @@ export function EntityWithEverything(
</div>
{/* Subject */}
{/*<ImportantBadge active={props.importantIndicatorActive} />*/}
<div class="flex items-center w-full gap-2 flex-1 min-w-0 @max-sm/split:flex-col @max-sm/split:items-start @max-sm/split:w-full @max-sm/split:gap-1">
<div class="flex items-center gap-2 flex-1 min-w-0 @max-sm/split:w-full @max-sm/split:justify-between @max-sm/split:min-w-0">
<div class="flex items-center w-full gap-2 flex-1 min-w-0 @max-md/split:flex-col @max-md/split:items-start @max-md/split:w-full @max-md/split:gap-1">
<div class="flex items-center gap-2 flex-1 min-w-0 @max-md/split:w-full @max-md/split:justify-between @max-md/split:min-w-0">
<div
class="shrink-0 truncate @max-sm/split:min-w-0 @max-sm/split:flex-1"
class="shrink-0 truncate @max-md/split:min-w-0 @max-md/split:flex-1"
classList={{
'font-regular text-ink-disabled': isSearch(),
'font-medium': !isSearch(),
}}
>
<Show when={isSearch()}>
<span class="@max-sm/split:hidden"> – </span>
<span class="@max-md/split:hidden"> – </span>
</Show>
<Show when={searchHighlightName()} fallback={props.entity.name}>
{(name) => (
Expand All @@ -594,23 +595,23 @@ export function EntityWithEverything(
</Show>
</div>
{/* Body snippet - inline in wide mode */}
<div class="truncate shrink grow opacity-60 @max-sm/split:hidden">
<div class="truncate shrink grow opacity-60 @max-md/split:hidden">
{props.entity.snippet}
</div>
{/* Timestamp inline with subject in narrow mode */}
<Show when={props.timestamp ?? props.entity.updatedAt}>
{(date) => {
const formattedDate = createFormattedDate(date());
return (
<span class="hidden @max-sm/split:inline shrink-0 whitespace-nowrap text-xs font-mono uppercase text-ink-extra-muted">
<span class="hidden @max-md/split:inline shrink-0 whitespace-nowrap text-xs font-mono uppercase text-ink-extra-muted">
{formattedDate()}
</span>
);
}}
</Show>
</div>
{/* Body snippet - below subject in narrow mode */}
<div class="hidden @max-sm/split:block truncate w-full text-xs opacity-60">
<div class="hidden @max-md/split:block truncate w-full text-xs opacity-60">
{props.entity.snippet}
</div>
</div>
Expand Down Expand Up @@ -640,11 +641,11 @@ export function EntityWithEverything(
};

return (
<div class="flex gap-2 items-center min-w-0 w-fit max-w-full overflow-hidden @max-sm/split:flex-col @max-sm/split:items-start @max-sm/split:w-full @max-sm/split:gap-1">
<span class="flex gap-1 truncate font-medium text-sm shrink-0 items-center @max-sm/split:w-full @max-sm/split:flex-col @max-sm/split:items-start @max-sm/split:gap-1">
<div class="flex items-center gap-2 w-full @max-sm/split:justify-between @max-sm/split:min-w-0">
<div class="flex gap-2 items-center min-w-0 w-fit max-w-full overflow-hidden @max-md/split:flex-col @max-md/split:items-start @max-md/split:w-full @max-md/split:gap-1">
<span class="flex gap-1 truncate font-medium text-sm shrink-0 items-center @max-md/split:w-full @max-md/split:flex-col @max-md/split:items-start @max-md/split:gap-1">
<div class="flex items-center gap-2 w-full @max-md/split:justify-between @max-md/split:min-w-0">
{/* Icon inline with title in narrow mode */}
<div class="hidden @max-sm/split:flex size-[1em] shrink-0 items-center justify-center relative group/icon-checkbox-nonemail">
<div class="hidden @max-md/split:flex size-[1em] shrink-0 items-center justify-center relative group/icon-checkbox-nonemail">
{/* Checkbox for narrow mode - shown on hover or when checked */}
<button
type="button"
Expand Down Expand Up @@ -693,7 +694,7 @@ export function EntityWithEverything(
</div>
</div>
<span
class="font-semibold truncate @max-sm/split:min-w-0 @max-sm/split:flex-1"
class="font-semibold truncate @max-md/split:min-w-0 @max-md/split:flex-1"
classList={{
'w-[20cqw]': !props.showUnrollNotifications,
}}
Expand All @@ -713,7 +714,7 @@ export function EntityWithEverything(
{(date) => {
const formattedDate = createFormattedDate(date());
return (
<span class="hidden @max-sm/split:inline shrink-0 whitespace-nowrap text-xs font-mono uppercase text-ink-extra-muted">
<span class="hidden @max-md/split:inline shrink-0 whitespace-nowrap text-xs font-mono uppercase text-ink-extra-muted">
{formattedDate()}
</span>
);
Expand All @@ -722,14 +723,14 @@ export function EntityWithEverything(
</div>

<Show when={showLatestMessageInfo()}>
<div class="flex items-center gap-1 @max-sm/split:w-full @max-sm/split:flex-col @max-sm/split:items-start @max-sm/split:gap-1">
<div class="flex items-center gap-1 @max-md/split:w-full @max-md/split:flex-col @max-md/split:items-start @max-md/split:gap-1">
{/*<ImportantBadge active={props.importantIndicatorActive} />*/}
<span class="font-medium shrink-0 truncate @max-sm/split:w-full">
<span class="font-medium shrink-0 truncate @max-md/split:w-full">
{userNameFromSender()}
</span>
<Show when={latestMessage()}>
{(lastMessage) => (
<div class="truncate shrink grow opacity-60 flex items-center @max-sm/split:w-full @max-sm/split:text-xs">
<div class="truncate shrink grow opacity-60 flex items-center @max-md/split:w-full @max-md/split:text-xs">
{/* TODO (seamus): Channels endpoint does not return any information about attachments. If we have an empty message, assume it's attachments.*/}
<Show
when={lastMessage().content.trim()}
Expand Down Expand Up @@ -809,13 +810,16 @@ export function EntityWithEverything(
class="everything-entity relative group/entity hover:bg-hover/30"
classList={{
'outline outline-accent/20 outline-offset-[-1px]':
props.selected && !props.checked,
!isTouchDevice && props.selected && !props.checked,
'!bg-accent/5 outline outline-accent/20 outline-offset-[-1px]':
props.checked,
'bracket outline outline-accent/20 outline-offset-[-1px]':
props.highlighted,
!isTouchDevice && props.selected,
'active:bracket active:outline active:outline-accent/20 active:outline-offset-[-1px]':
isTouchDevice && !props.checked,
}}
onMouseOver={(e) => {
if (isTouchDevice) return;
if (!didCursorMove(e)) {
return;
}
Expand All @@ -829,7 +833,7 @@ export function EntityWithEverything(
<div
data-entity
data-entity-id={props.entity.id}
class="w-full min-w-0 grid flex-1 items-center suppress-css-bracket grid-cols-[2rem_1fr_auto] @max-sm/split:flex @max-sm/split:flex-col pr-2 @max-sm/split:px-2 @max-sm/split:py-2"
class="w-full min-w-0 grid flex-1 items-center suppress-css-bracket grid-cols-[2rem_1fr_auto] @max-md/split:flex @max-md/split:flex-col pr-2 @max-md/split:px-2 @max-md/split:py-2"
onClick={(e) => {
if (blocksNavigation(e)) return;
props.onClick?.(props.entity, e);
Expand Down Expand Up @@ -857,7 +861,7 @@ export function EntityWithEverything(
>
<button
type="button"
class="col-1 size-full relative group/button flex items-center justify-center bracket-never @max-sm/split:hidden"
class="col-1 size-full relative group/button flex items-center justify-center bracket-never @max-md/split:hidden"
onClick={(e) => {
props.onChecked?.(!props.checked, e.shiftKey);
}}
Expand All @@ -876,27 +880,27 @@ export function EntityWithEverything(
</Show>
</div>
<Show when={props.showLeftColumnIndicator && !props.checked}>
<div class="absolute inset-0 flex items-center justify-center -z-1 @max-sm/split:hidden">
<div class="absolute inset-0 flex items-center justify-center -z-1 @max-md/split:hidden">
<UnreadIndicator active={props.unreadIndicatorActive} />
</div>
</Show>
</button>
{/* Left Column Indicator(s) */}
{/* Icon and name - top left on mobile, first item on desktop */}
<div
class="min-h-10 min-w-[50px] flex flex-row items-center gap-2 col-2 @max-sm/split:col-auto @max-sm/split:w-full @max-sm/split:min-h-0 @max-sm/split:items-start"
class="min-h-10 min-w-[50px] flex flex-row items-center gap-2 col-2 @max-md/split:col-auto @max-md/split:w-full @max-md/split:min-h-0 @max-md/split:items-start"
classList={{
grow: props.contentPlacement === 'bottom-row',
'opacity-70': props.fadeIfRead && !props.unreadIndicatorActive,
}}
>
{/* Icon/Checkbox container - in narrow mode, shows icon by default, checkbox on hover */}
{/* For emails, icon is inline with sender, so hide this container in narrow mode */}
<div class="flex size-5 shrink-0 items-center justify-center relative group/icon-checkbox @max-sm/split:hidden">
<div class="flex size-5 shrink-0 items-center justify-center relative group/icon-checkbox @max-md/split:hidden">
{/* Checkbox for narrow mode - shown on hover or when checked, hidden at larger widths */}
<button
type="button"
class="hidden @max-sm/split:flex @min-sm/split:hidden absolute inset-0 items-center justify-center opacity-0 group-hover/icon-checkbox:opacity-100 transition-opacity"
class="hidden @max-md/split:flex @min-md/split:hidden absolute inset-0 items-center justify-center opacity-0 group-hover/icon-checkbox:opacity-100 transition-opacity"
classList={{
'opacity-100': props.checked,
}}
Expand All @@ -919,9 +923,9 @@ export function EntityWithEverything(
</button>
{/* Icon - hidden on hover in narrow mode when not checked */}
<div
class="flex items-center justify-center @max-sm/split:group-hover/icon-checkbox:opacity-0 @max-sm/split:transition-opacity"
class="flex items-center justify-center @max-md/split:group-hover/icon-checkbox:opacity-0 @max-md/split:transition-opacity"
classList={{
'@max-sm/split:opacity-0': props.checked,
'@max-md/split:opacity-0': props.checked,
}}
>
<Show
Expand All @@ -944,12 +948,12 @@ export function EntityWithEverything(
</div>
{/* Date and user - top right on mobile, end on desktop */}
<div
class="row-1 ml-2 @md:ml-4 self-center min-w-0 col-3 @max-sm/split:col-auto @max-sm/split:row-auto @max-sm/split:ml-0 @max-sm/split:mt-1 @max-sm/split:self-start @max-sm/split:w-full"
class="row-1 ml-2 @md:ml-4 self-center min-w-0 col-3 @max-md/split:col-auto @max-md/split:row-auto @max-md/split:ml-0 @max-md/split:mt-1 @max-md/split:self-start @max-md/split:w-full"
classList={{
'opacity-50': props.fadeIfRead && !props.unreadIndicatorActive,
}}
>
<div class="flex flex-row items-center justify-end gap-2 min-w-0 @max-sm/split:justify-start @max-sm/split:flex-wrap">
<div class="flex flex-row items-center justify-end gap-2 min-w-0 @max-md/split:justify-start @max-md/split:flex-wrap">
<Show when={properties().length > 0}>
<div class="pr-2 overflow-hidden shrink min-w-0">
<PropertyPills properties={properties()} />
Expand All @@ -973,7 +977,7 @@ export function EntityWithEverything(
{(date) => {
const formattedDate = createFormattedDate(date());
return (
<span class="shrink-0 whitespace-nowrap text-xs font-mono uppercase text-ink-extra-muted @max-sm/split:hidden">
<span class="shrink-0 whitespace-nowrap text-xs font-mono uppercase text-ink-extra-muted @max-md/split:hidden">
{formattedDate()}
</span>
);
Expand Down Expand Up @@ -1012,7 +1016,7 @@ export function EntityWithEverything(
</div>
{/* Content Hits from Search */}
<Show when={contentHitData().length > 0}>
<div class="relative row-2 col-2 col-end-4 pb-2 @max-sm/split:row-auto @max-sm/split:col-auto @max-sm/split:w-full @max-sm/split:mt-1">
<div class="relative row-2 col-2 col-end-4 pb-2 @max-md/split:row-auto @max-md/split:col-auto @max-md/split:w-full @max-md/split:mt-1">
<CollapsibleList items={contentHitData()} threadBorder>
{(data, index, count) => (
<ContentHitRow
Expand All @@ -1035,7 +1039,7 @@ export function EntityWithEverything(
contentHitData().length === 0
}
>
<div class="relative col-2 col-end-4 pb-2 @max-sm/split:col-auto @max-sm/split:w-full @max-sm/split:mt-1">
<div class="relative col-2 col-end-4 pb-2 @max-md/split:col-auto @max-md/split:w-full @max-md/split:mt-1">
<CollapsibleList items={notDoneNotifications()} threadBorder>
{(notification) => (
<NotificationRow
Expand Down
Loading