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
5 changes: 5 additions & 0 deletions .changeset/feat-change-unverified-view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

Change unverified device flow.
5 changes: 5 additions & 0 deletions .changeset/feat_rework_mobile_view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

Modify large parts of the mobile view of Sable!
9 changes: 9 additions & 0 deletions src/app/components/UserQuickToolsProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { UserQuickTools } from '$pages/client/sidebar/UserQuickTools';

export function UserQuickToolsProvider() {
const screenSize = useScreenSizeContext();
const compact = screenSize === ScreenSize.Mobile;
if (!compact) return null;
return <UserQuickTools compact />;
}
6 changes: 5 additions & 1 deletion src/app/components/message/modals/GlobalModalManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export function GlobalModalManager() {
focusTrapOptions={{
initialFocus: false,
onDeactivate: close,
clickOutsideDeactivates: true,
allowOutsideClick: (e: { preventDefault?: () => void }) => {
if (e.preventDefault) e.preventDefault();
close();
return false;
},
escapeDeactivates: stopPropagation,
}}
>
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/message/modals/MessageForward.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import * as Sentry from '@sentry/react';
import { isRoomPrivate } from '$utils/roomVisibility';
import { canForwardEvent } from '$utils/room';
import * as prefix from '$unstable/prefixes';
import { RoomSearchModal } from '$features/search';
import { SearchWrapper } from '$features/navigate';
const debugLog = createDebugLogger('MessageForward');

// Message forwarding component
Expand Down Expand Up @@ -270,7 +270,7 @@ export function MessageForwardInternal({

if (!forwardable) return null;

return <RoomSearchModal requestClose={onClose} pickRoom={pickRoom} />;
return <SearchWrapper requestClose={onClose} pickRoom={pickRoom} />;
}

type MessageForwardItemProps = {
Expand Down
21 changes: 19 additions & 2 deletions src/app/components/message/modals/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ export function OptionMenu({
onReactionToggle(mEvent.getId() ?? '', key, shortcode);
onTotalClose();
}}
count={isModal ? 6 : 4}
count={isModal ? 8 : 4}
/>
)}
<Box direction="Column" gap="100" className={css.MessageMenuGroup}>
Expand All @@ -615,6 +615,23 @@ export function OptionMenu({
</Text>
</MenuItem>
)}

{canEditEvent(mx, mEvent) && onEditId && isModal && (
<MenuItem
size="300"
after={menuIcon(PencilSimple)}
radii="300"
data-event-id={mEvent.getId()}
onClick={() => {
onEditId(mEvent.getId());
onTotalClose();
}}
>
<Text className={css.MessageMenuItemText} as="span" size="T300" truncate>
Edit Message
</Text>
</MenuItem>
)}
{/* Only show "Add to User Sticker Pack" if the sticker isn't already in the default pack and isn't encrypted */}
{isStickerMessage &&
mEvent.getContent().url &&
Expand Down Expand Up @@ -670,7 +687,7 @@ export function OptionMenu({
</Text>
</MenuItem>
)}
{canEditEvent(mx, mEvent) && onEditId && (
{canEditEvent(mx, mEvent) && onEditId && !isModal && (
<MenuItem
size="300"
after={menuIcon(PencilSimple)}
Expand Down
1 change: 0 additions & 1 deletion src/app/components/sidebar/Sidebar.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ export const SidebarItemBottom = recipe({
base: [
DefaultReset,
{
minHeight: toRem(30),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { keyframes, style } from '@vanilla-extract/css';
import { color, config, toRem } from 'folds';

const slideUp = keyframes({
from: {
opacity: 0,
transform: 'translateY(-100%)',
},
to: {
opacity: 1,
transform: 'translateY(0)',
},
});

const slideDown = keyframes({
from: {
opacity: 1,
transform: 'translateY(0)',
},
to: {
opacity: 0,
transform: 'translateY(100%)',
},
});

export const Container = style({
position: 'fixed',
top: 'env(safe-area-inset-top, 0)',
left: '50%',
transform: 'translateX(-50%)',
zIndex: 9998,
width: `min(100%, ${toRem(520)})`,
padding: config.space.S400,
pointerEvents: 'none',
});

export const Banner = style({
pointerEvents: 'all',
display: 'flex',
flexDirection: 'column',
gap: config.space.S300,
backgroundColor: color.Surface.Container,
color: color.Surface.OnContainer,
border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`,
borderRadius: toRem(16),
padding: config.space.S400,
boxShadow: `0 ${toRem(8)} ${toRem(32)} rgba(0, 0, 0, 0.45), 0 ${toRem(2)} ${toRem(8)} rgba(0, 0, 0, 0.3)`,
animationName: slideUp,
animationDuration: '300ms',
animationTimingFunction: 'cubic-bezier(0.22, 0.8, 0.6, 1)',
animationFillMode: 'both',

selectors: {
'&[data-dismissing=true]': {
animationName: slideDown,
animationDuration: '220ms',
animationTimingFunction: 'cubic-bezier(0.4, 0, 1, 1)',
animationFillMode: 'both',
},
},
});

export const Header = style({
display: 'flex',
alignItems: 'flex-start',
gap: config.space.S300,
});

export const HeaderText = style({
flex: 1,
minWidth: 0,
display: 'flex',
flexDirection: 'column',
gap: toRem(4),
});

export const Actions = style({
display: 'flex',
gap: config.space.S200,
justifyContent: 'flex-end',
flexWrap: 'wrap',
});
80 changes: 80 additions & 0 deletions src/app/components/unverified-notice/UnverifiedNoticeBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Box, Button, color, Text } from 'folds';
import { sizedIcon } from '$components/icons/phosphor';
import * as css from './UnverifiedNoticeBanner.css';
import { useOpenSettings } from '$features/settings';
import { ShieldWarningIcon } from '@phosphor-icons/react';
import { useIsUnverified, useUnverifiedDevices } from '$pages/client/sidebar/UserMenuTab';
import { getLocalStorageItem, setLocalStorageItem } from '$state/utils/atomWithLocalStorage';
import { useEffect, useState } from 'react';

export function UnverifiedNoticeBanner() {
const openSettings = useOpenSettings();

const isUnverified = useIsUnverified();
const unverifiedDeviceCount = useUnverifiedDevices();
const hasUnverified =
isUnverified || (unverifiedDeviceCount !== undefined && unverifiedDeviceCount > 0);
const [dismissCount, setDismissCount] = useState(unverifiedDeviceCount);

const [isDismissedNotice, setIsDismissedNotice] = useState(
getLocalStorageItem('dismissNotice', false)
);
useEffect(() => {
if (
unverifiedDeviceCount &&
dismissCount &&
unverifiedDeviceCount > 0 &&
dismissCount < unverifiedDeviceCount
) {
setLocalStorageItem('dismissNotice', false);
setIsDismissedNotice(false);
}
setDismissCount(unverifiedDeviceCount);
}, [unverifiedDeviceCount, dismissCount]);

if (!hasUnverified || isDismissedNotice) return null;

const handleVerify = () => {
openSettings('devices');
};
const handleDismiss = () => {
setLocalStorageItem('dismissNotice', true);
setIsDismissedNotice(true);
};

return (
<div className={css.Container}>
<div className={css.Banner} role="region" aria-label="Crash reporting prompt">
<div
className={css.Header}
style={{ color: isUnverified ? color.Critical.OnContainer : color.Warning.OnContainer }}
>
{sizedIcon(ShieldWarningIcon, '400')}
<div className={css.HeaderText}>
<Text size="H4">
{isUnverified
? 'This Device is Unverified!'
: `You have ${unverifiedDeviceCount === 1 ? 'an' : ''} Unverified Device${unverifiedDeviceCount !== 1 ? 's' : ''}!`}
</Text>
<Text
size="T300"
priority="300"
style={{ textAlign: 'justify', color: color.Surface.OnContainer }}
>
An unverified device is unable to read old encrypted messages and might result in
other people being unable to read your messages or to send you messages!
</Text>
</div>
</div>
<Box className={css.Actions}>
<Button variant="Secondary" fill="Soft" size="300" radii="300" onClick={handleDismiss}>
<Text size="B300">Dismiss</Text>
</Button>
<Button variant="Primary" fill="Solid" size="300" radii="300" onClick={handleVerify}>
<Text size="B300">Verify</Text>
</Button>
</Box>
</div>
</div>
);
}
1 change: 1 addition & 0 deletions src/app/components/unverified-notice/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './UnverifiedNoticeBanner';
10 changes: 8 additions & 2 deletions src/app/components/user-profile/UserHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ export function UserHero({
} as CSSProperties),
}}
>
<Box direction="Row" gap="100" style={{ height: '100%', width: '100%' }}>
<Box
direction="Row"
gap="100"
style={{ height: '100%', maxWidth: allowEditing ? toRem(210) : '100%' }}
>
{isFullStatus ? (
<Scroll visibility="Hover" hideTrack style={{ height: '100%', flex: 1 }}>
<Text
Expand All @@ -224,6 +228,7 @@ export function UserHero({
wordBreak: 'break-word',
fontStyle: allowEditing && !status ? 'italic' : 'normal',
}}
truncate={allowEditing}
>
{status || (allowEditing && "What's on your mind?")}
</Text>
Expand All @@ -240,12 +245,13 @@ export function UserHero({
fontStyle: allowEditing && !status ? 'italic' : 'normal',
opacity: allowEditing && !status ? config.opacity.Placeholder : 1,
}}
truncate={allowEditing}
>
{status || (allowEditing && "What's on your mind?")}
</Text>
)}

{isExpandable && (
{isExpandable && !allowEditing && (
<Box
shrink="No"
alignItems="Center"
Expand Down
Loading
Loading