Skip to content

Commit

Permalink
add option to edit pack meta
Browse files Browse the repository at this point in the history
  • Loading branch information
ajbura committed Jan 12, 2025
1 parent 77ebd1a commit e9d8a7b
Show file tree
Hide file tree
Showing 8 changed files with 524 additions and 163 deletions.
409 changes: 355 additions & 54 deletions src/app/components/image-pack-view/ImagePackContent.tsx

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions src/app/components/image-pack-view/ImagePackView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,11 @@ export function ImagePackView({ imagePack, requestClose }: ImagePackViewProps) {
<Box grow="Yes">
<Scroll hideTrack visibility="Hover">
<PageContent>
<Box direction="Column" gap="700">
{room ? (
<RoomImagePack room={room} imagePack={imagePack} />
) : (
<UserImagePack imagePack={imagePack} />
)}
</Box>
{room ? (
<RoomImagePack room={room} imagePack={imagePack} />
) : (
<UserImagePack imagePack={imagePack} />
)}
</PageContent>
</Scroll>
</Box>
Expand Down
73 changes: 23 additions & 50 deletions src/app/components/image-pack-view/ImageTile.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { MouseEventHandler, useState } from 'react';
import { Chip, Icon, Icons, Text, PopOut, Menu, RectCords } from 'folds';
import FocusTrap from 'focus-trap-react';
import { stopPropagation } from '../../utils/keyboard';
import { UsageSelector, useUsageStr } from './UsageSelector';
import React, { useCallback } from 'react';
import { Badge, Box, Chip, Text } from 'folds';
import { useUsageStr } from './UsageSwitcher';
import { mxcUrlToHttp } from '../../utils/matrix';
import * as css from './style.css';
import { ImageUsage, PackImageReader } from '../../plugins/custom-emoji';
Expand All @@ -13,21 +11,15 @@ type ImageTileProps = {
useAuthentication: boolean;
packUsage: ImageUsage[];
image: PackImageReader;
canEdit?: boolean;
};
export function ImageTile({ image, packUsage, useAuthentication }: ImageTileProps) {
export function ImageTile({ image, packUsage, useAuthentication, canEdit }: ImageTileProps) {
const mx = useMatrixClient();
const getUsageStr = useUsageStr();
const usage = image.usage ?? packUsage;

const [menuCords, setMenuCords] = useState<RectCords>();

const handleChange = (usg: ImageUsage[]) => {
const handleChange = useCallback((usg: ImageUsage[]) => {
console.log(usg);
};

const handleSelectUsage: MouseEventHandler<HTMLButtonElement> = (event) => {
setMenuCords(event.currentTarget.getBoundingClientRect());
};
}, []);

return (
<SettingTile
Expand All @@ -41,41 +33,22 @@ export function ImageTile({ image, packUsage, useAuthentication }: ImageTileProp
title={image.shortcode}
description={image.body}
after={
<>
<Chip
variant="Secondary"
radii="Pill"
after={<Icon src={Icons.ChevronBottom} size="100" />}
onClick={handleSelectUsage}
>
<Text size="B300">{getUsageStr(usage)}</Text>
</Chip>
<PopOut
anchor={menuCords}
offset={5}
position="Bottom"
align="End"
content={
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: () => setMenuCords(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) =>
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
isKeyBackward: (evt: KeyboardEvent) =>
evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
escapeDeactivates: stopPropagation,
}}
>
<Menu>
<UsageSelector selected={usage} onChange={handleChange} />
</Menu>
</FocusTrap>
}
/>
</>
canEdit ? (
<Box shrink="No" alignItems="Center" gap="200">
<Chip variant="Secondary" radii="Pill" outlined>
<Text size="B300">Edit</Text>
</Chip>
</Box>
) : undefined
}
/>
>
{image.usage && getUsageStr(image.usage) !== getUsageStr(packUsage) && (
<Box>
<Badge variant="Secondary" size="400" radii="300" outlined>
<Text size="L400">{getUsageStr(image.usage)}</Text>
</Badge>
</Box>
)}
</SettingTile>
);
}
51 changes: 0 additions & 51 deletions src/app/components/image-pack-view/UsageSelector.tsx

This file was deleted.

115 changes: 115 additions & 0 deletions src/app/components/image-pack-view/UsageSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { MouseEventHandler, useMemo, useState } from 'react';
import { Box, Button, config, Icon, Icons, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
import FocusTrap from 'focus-trap-react';
import { ImageUsage } from '../../plugins/custom-emoji';
import { stopPropagation } from '../../utils/keyboard';

export const useUsageStr = (): ((usage: ImageUsage[]) => string) => {
const getUsageStr = (usage: ImageUsage[]): string => {
const sticker = usage.includes(ImageUsage.Sticker);
const emoticon = usage.includes(ImageUsage.Emoticon);

if (sticker && emoticon) return 'Emoji & Sticker';
if (sticker) return 'Sticker';
if (emoticon) return 'Emoji';
return 'Both';
};
return getUsageStr;
};

type UsageSelectorProps = {
selected: ImageUsage[];
onChange: (usage: ImageUsage[]) => void;
};
export function UsageSelector({ selected, onChange }: UsageSelectorProps) {
const getUsageStr = useUsageStr();

const selectedUsageStr = getUsageStr(selected);
const isSelected = (usage: ImageUsage[]) => getUsageStr(usage) === selectedUsageStr;

const allUsages: ImageUsage[][] = useMemo(
() => [[ImageUsage.Emoticon], [ImageUsage.Sticker], [ImageUsage.Sticker, ImageUsage.Emoticon]],
[]
);

return (
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
{allUsages.map((usage) => (
<MenuItem
key={getUsageStr(usage)}
size="300"
variant={isSelected(usage) ? 'SurfaceVariant' : 'Surface'}
aria-selected={isSelected(usage)}
radii="300"
onClick={() => onChange(usage)}
>
<Box grow="Yes">
<Text size="T300">{getUsageStr(usage)}</Text>
</Box>
</MenuItem>
))}
</Box>
);
}

type UsageSwitcherProps = {
usage: ImageUsage[];
canEdit?: boolean;
onChange: (usage: ImageUsage[]) => void;
};
export function UsageSwitcher({ usage, onChange, canEdit }: UsageSwitcherProps) {
const getUsageStr = useUsageStr();

const [menuCords, setMenuCords] = useState<RectCords>();

const handleSelectUsage: MouseEventHandler<HTMLButtonElement> = (event) => {
setMenuCords(event.currentTarget.getBoundingClientRect());
};

return (
<>
<Button
variant="Secondary"
fill="Soft"
size="300"
radii="300"
outlined
aria-disabled={!canEdit}
after={canEdit && <Icon src={Icons.ChevronBottom} size="100" />}
onClick={canEdit ? handleSelectUsage : undefined}
>
<Text size="B300">{getUsageStr(usage)}</Text>
</Button>
<PopOut
anchor={menuCords}
offset={5}
position="Bottom"
align="End"
content={
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: () => setMenuCords(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) =>
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
isKeyBackward: (evt: KeyboardEvent) =>
evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
escapeDeactivates: stopPropagation,
}}
>
<Menu>
<UsageSelector
selected={usage}
onChange={(usg) => {
setMenuCords(undefined);
onChange(usg);
}}
/>
</Menu>
</FocusTrap>
}
/>
</>
);
}
12 changes: 11 additions & 1 deletion src/app/components/image-pack-view/style.css.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { style } from '@vanilla-extract/css';
import { DefaultReset, toRem } from 'folds';
import { config, DefaultReset, toRem } from 'folds';

export const ImagePackImage = style([
DefaultReset,
Expand All @@ -9,3 +9,13 @@ export const ImagePackImage = style([
objectFit: 'contain',
},
]);

export const UnsavedMenu = style({
position: 'sticky',
padding: config.space.S200,
paddingLeft: config.space.S400,
top: config.space.S400,
left: config.space.S400,
right: 0,
zIndex: 1,
});
4 changes: 4 additions & 0 deletions src/app/plugins/custom-emoji/PackMetaReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,8 @@ export class PackMetaReader {

return knownUsage;
}

get content(): PackMeta {
return this.meta;
}
}
11 changes: 11 additions & 0 deletions src/app/plugins/custom-emoji/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ import { EmoteRoomsContent } from './types';
import { StateEvent } from '../../../types/matrix/room';
import { getAccountData, getStateEvents } from '../../utils/room';
import { AccountDataEvent } from '../../../types/matrix/accountData';
import { PackMetaReader } from './PackMetaReader';

export function packMetaEqual(a: PackMetaReader, b: PackMetaReader): boolean {
return (
a.name === b.name &&
a.avatar === b.avatar &&
a.attribution === b.attribution &&
a.usage.length === b.usage.length &&
a.usage.every((u) => b.usage.includes(u))
);
}

export function makeImagePacks(packEvents: MatrixEvent[]): ImagePack[] {
return packEvents.reduce<ImagePack[]>((imagePacks, packEvent) => {
Expand Down

0 comments on commit e9d8a7b

Please sign in to comment.