diff --git a/src/app/components/image-editor/ImageEditor.css.ts b/src/app/components/image-editor/ImageEditor.css.ts
new file mode 100644
index 000000000..6b42c22da
--- /dev/null
+++ b/src/app/components/image-editor/ImageEditor.css.ts
@@ -0,0 +1,35 @@
+import { style } from '@vanilla-extract/css';
+import { DefaultReset, color, config } from 'folds';
+
+export const ImageEditor = style([
+ DefaultReset,
+ {
+ height: '100%',
+ },
+]);
+
+export const ImageEditorHeader = style([
+ DefaultReset,
+ {
+ paddingLeft: config.space.S200,
+ paddingRight: config.space.S200,
+ borderBottomWidth: config.borderWidth.B300,
+ flexShrink: 0,
+ gap: config.space.S200,
+ },
+]);
+
+export const ImageEditorContent = style([
+ DefaultReset,
+ {
+ backgroundColor: color.Background.Container,
+ color: color.Background.OnContainer,
+ overflow: 'hidden',
+ },
+]);
+
+export const Image = style({
+ width: '100%',
+ height: '100%',
+ objectFit: 'contain',
+});
diff --git a/src/app/components/image-editor/ImageEditor.tsx b/src/app/components/image-editor/ImageEditor.tsx
new file mode 100644
index 000000000..1ec474e8b
--- /dev/null
+++ b/src/app/components/image-editor/ImageEditor.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import classNames from 'classnames';
+import { Box, Chip, Header, Icon, IconButton, Icons, Text, as } from 'folds';
+import * as css from './ImageEditor.css';
+
+export type ImageEditorProps = {
+ name: string;
+ url: string;
+ requestClose: () => void;
+};
+
+export const ImageEditor = as<'div', ImageEditorProps>(
+ ({ className, name, url, requestClose, ...props }, ref) => {
+ const handleApply = () => {
+ //
+ };
+
+ return (
+
+
+
+
+
+
+
+ Image Editor
+
+
+
+
+ Save
+
+
+
+
+
+
+
+ );
+ }
+);
diff --git a/src/app/components/image-editor/index.ts b/src/app/components/image-editor/index.ts
new file mode 100644
index 000000000..51907cbb7
--- /dev/null
+++ b/src/app/components/image-editor/index.ts
@@ -0,0 +1 @@
+export * from './ImageEditor';
diff --git a/src/app/features/settings/Account.tsx b/src/app/features/settings/Account.tsx
index 7ab14aa63..e4d414533 100644
--- a/src/app/features/settings/Account.tsx
+++ b/src/app/features/settings/Account.tsx
@@ -1,17 +1,38 @@
-import React, { useCallback, useEffect } from 'react';
-import { Box, Text, IconButton, Icon, Icons, Scroll, Input, Avatar, Button, Chip } from 'folds';
+import React, { useCallback, useEffect, useState } from 'react';
+import {
+ Box,
+ Text,
+ IconButton,
+ Icon,
+ Icons,
+ Scroll,
+ Input,
+ Avatar,
+ Button,
+ Chip,
+ Overlay,
+ OverlayBackdrop,
+ OverlayCenter,
+ Modal,
+} from 'folds';
+import FocusTrap from 'focus-trap-react';
import { Page, PageContent, PageHeader } from '../../components/page';
import { SequenceCard } from '../../components/sequence-card';
import { SequenceCardStyle } from './styles.css';
import { SettingTile } from '../../components/setting-tile';
import { useMatrixClient } from '../../hooks/useMatrixClient';
-import { useUserProfile } from '../../hooks/useUserProfile';
+import { UserProfile, useUserProfile } from '../../hooks/useUserProfile';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { UserAvatar } from '../../components/user-avatar';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { nameInitials } from '../../utils/common';
import { copyToClipboard } from '../../utils/dom';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
+import { useFilePicker } from '../../hooks/useFilePicker';
+import { useObjectURL } from '../../hooks/useObjectURL';
+import { stopPropagation } from '../../utils/keyboard';
+import { ImageEditor } from '../../components/image-editor';
+import { ModalWide } from '../../styles/Modal.css';
function MatrixId() {
const mx = useMatrixClient();
@@ -39,17 +60,95 @@ function MatrixId() {
);
}
-function Profile() {
+type ProfileAvatarProps = {
+ profile: UserProfile;
+ userId: string;
+};
+function ProfileAvatar({ profile, userId }: ProfileAvatarProps) {
const mx = useMatrixClient();
const useAuthentication = useMediaAuthentication();
- const userId = mx.getUserId()!;
- const profile = useUserProfile(userId);
const defaultDisplayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId;
const avatarUrl = profile.avatarUrl
? mxcUrlToHttp(mx, profile.avatarUrl, useAuthentication, 96, 96, 'crop') ?? undefined
: undefined;
+ const [imageFile, setImageFile] = useState();
+ const imageFileURL = useObjectURL(imageFile);
+
+ const pickFile = useFilePicker(setImageFile, false);
+
+ const handleImageCropperClose = useCallback(() => {
+ setImageFile(undefined);
+ }, []);
+
+ return (
+
+ Avatar
+
+ }
+ before={
+
+ {nameInitials(defaultDisplayName)}}
+ />
+
+ }
+ >
+
+
+ {avatarUrl && (
+
+ )}
+
+ {imageFileURL && (
+ }>
+
+
+
+
+
+
+
+
+ )}
+
+
+ );
+}
+
+function Profile() {
+ const mx = useMatrixClient();
+ const userId = mx.getUserId()!;
+ const profile = useUserProfile(userId);
+ const defaultDisplayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId;
+
return (
Profile
@@ -59,33 +158,7 @@ function Profile() {
direction="Column"
gap="400"
>
-
- Avatar
-
- }
- before={
-
- {nameInitials(defaultDisplayName)}}
- />
-
- }
- >
-
-
- {avatarUrl && (
-
- )}
-
-
+
@@ -136,7 +209,7 @@ function ContactInformation() {
{emailIds?.map((email) => (
-
+
{email.address}
))}