New room settings, add customizable power levels and dev tools (#2222)
* WIP - add room settings dialog * join rule setting - WIP * show emojis & stickers in room settings - WIP * restyle join rule switcher * Merge branch 'dev' into new-room-settings * add join rule hook * open room settings from global state * open new room settings from all places * rearrange settings menu item * add option for creating new image pack * room devtools - WIP * render room state events as list * add option to open state event * add option to edit state event * refactor text area code editor into hook * add option to send message and state event * add cutout card component * add hook for room account data * display room account data - WIP * refactor global account data editor component * add account data editor in room * fix font style in devtool * show state events in compact form * add option to delete room image pack * add server badge component * add member tile component * render members in room settings * add search in room settings member * add option to reset member search * add filter in room members * fix member virtual item key * remove color from serve badge in room members * show room in settings * fix loading indicator position * power level tags in room setting - WIP * generate fallback tag in backward compatible way * add color picker * add powers editor - WIP * add props to stop adding emoji to recent usage * add beta feature notice badge * add types for power level tag icon * refactor image pack rooms code to hook * option for adding new power levels tags * remove console log * refactor power icon * add option to edit power level tags * remove power level from powers pill * fix power level labels * add option to delete power levels * fix long power level name shrinks power integer * room permissions - WIP * add power level selector component * add room permissions * move user default permission setting to other group * add power permission peek menu * fix weigh of power switch text * hide above for max power in permission switcher * improve beta badge description * render room profile in room settings * add option to edit room profile * make room topic input text area * add option to enable room encryption in room settings * add option to change message history visibility * add option to change join rule * add option for addresses in room settings * close encryption dialog after enabling
This commit is contained in:
parent
00f3df8719
commit
286983c833
73 changed files with 6196 additions and 420 deletions
21
src/app/components/power/PowerColorBadge.tsx
Normal file
21
src/app/components/power/PowerColorBadge.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
import { as } from 'folds';
|
||||
import classNames from 'classnames';
|
||||
import * as css from './style.css';
|
||||
|
||||
type PowerColorBadgeProps = {
|
||||
color?: string;
|
||||
};
|
||||
export const PowerColorBadge = as<'span', PowerColorBadgeProps>(
|
||||
({ as: AsPowerColorBadge = 'span', color, className, style, ...props }, ref) => (
|
||||
<AsPowerColorBadge
|
||||
className={classNames(css.PowerColorBadge, className)}
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
);
|
||||
15
src/app/components/power/PowerIcon.tsx
Normal file
15
src/app/components/power/PowerIcon.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import * as css from './style.css';
|
||||
import { JUMBO_EMOJI_REG } from '../../utils/regex';
|
||||
|
||||
type PowerIconProps = css.PowerIconVariants & {
|
||||
iconSrc: string;
|
||||
name?: string;
|
||||
};
|
||||
export function PowerIcon({ size, iconSrc, name }: PowerIconProps) {
|
||||
return JUMBO_EMOJI_REG.test(iconSrc) ? (
|
||||
<span className={css.PowerIcon({ size })}>{iconSrc}</span>
|
||||
) : (
|
||||
<img className={css.PowerIcon({ size })} src={iconSrc} alt={name} />
|
||||
);
|
||||
}
|
||||
94
src/app/components/power/PowerSelector.tsx
Normal file
94
src/app/components/power/PowerSelector.tsx
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import React, { forwardRef, MouseEventHandler, ReactNode, useState } from 'react';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import { Box, config, Menu, MenuItem, PopOut, Scroll, Text, toRem, RectCords } from 'folds';
|
||||
import { getPowers, PowerLevelTags } from '../../hooks/usePowerLevelTags';
|
||||
import { PowerColorBadge } from './PowerColorBadge';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
|
||||
type PowerSelectorProps = {
|
||||
powerLevelTags: PowerLevelTags;
|
||||
value: number;
|
||||
onChange: (value: number) => void;
|
||||
};
|
||||
export const PowerSelector = forwardRef<HTMLDivElement, PowerSelectorProps>(
|
||||
({ powerLevelTags, value, onChange }, ref) => (
|
||||
<Menu
|
||||
ref={ref}
|
||||
style={{
|
||||
maxHeight: '75vh',
|
||||
maxWidth: toRem(300),
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
<Box grow="Yes">
|
||||
<Scroll size="0" hideTrack visibility="Hover">
|
||||
<div style={{ padding: config.space.S100 }}>
|
||||
{getPowers(powerLevelTags).map((power) => {
|
||||
const selected = value === power;
|
||||
const tag = powerLevelTags[power];
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={power}
|
||||
aria-pressed={selected}
|
||||
radii="300"
|
||||
onClick={selected ? undefined : () => onChange(power)}
|
||||
before={<PowerColorBadge color={tag.color} />}
|
||||
after={<Text size="L400">{power}</Text>}
|
||||
>
|
||||
<Text style={{ flexGrow: 1 }} size="B400" truncate>
|
||||
{tag.name}
|
||||
</Text>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Scroll>
|
||||
</Box>
|
||||
</Menu>
|
||||
)
|
||||
);
|
||||
|
||||
type PowerSwitcherProps = PowerSelectorProps & {
|
||||
children: (handleOpen: MouseEventHandler<HTMLButtonElement>, opened: boolean) => ReactNode;
|
||||
};
|
||||
export function PowerSwitcher({ powerLevelTags, value, onChange, children }: PowerSwitcherProps) {
|
||||
const [menuCords, setMenuCords] = useState<RectCords>();
|
||||
|
||||
const handleOpen: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||
setMenuCords(evt.currentTarget.getBoundingClientRect());
|
||||
};
|
||||
|
||||
return (
|
||||
<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,
|
||||
}}
|
||||
>
|
||||
<PowerSelector
|
||||
powerLevelTags={powerLevelTags}
|
||||
value={value}
|
||||
onChange={(v) => {
|
||||
onChange(v);
|
||||
setMenuCords(undefined);
|
||||
}}
|
||||
/>
|
||||
</FocusTrap>
|
||||
}
|
||||
>
|
||||
{children(handleOpen, !!menuCords)}
|
||||
</PopOut>
|
||||
);
|
||||
}
|
||||
3
src/app/components/power/index.ts
Normal file
3
src/app/components/power/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from './PowerColorBadge';
|
||||
export * from './PowerIcon';
|
||||
export * from './PowerSelector';
|
||||
73
src/app/components/power/style.css.ts
Normal file
73
src/app/components/power/style.css.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { createVar, style } from '@vanilla-extract/css';
|
||||
import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
|
||||
import { color, config, DefaultReset, toRem } from 'folds';
|
||||
|
||||
export const PowerColorBadge = style({
|
||||
display: 'inline-block',
|
||||
flexShrink: 0,
|
||||
width: toRem(16),
|
||||
height: toRem(16),
|
||||
backgroundColor: color.Surface.OnContainer,
|
||||
borderRadius: config.radii.Pill,
|
||||
border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`,
|
||||
});
|
||||
|
||||
const PowerIconSize = createVar();
|
||||
export const PowerIcon = recipe({
|
||||
base: [
|
||||
DefaultReset,
|
||||
{
|
||||
display: 'inline-flex',
|
||||
height: PowerIconSize,
|
||||
minWidth: PowerIconSize,
|
||||
fontSize: PowerIconSize,
|
||||
lineHeight: PowerIconSize,
|
||||
borderRadius: config.radii.R300,
|
||||
cursor: 'default',
|
||||
},
|
||||
],
|
||||
variants: {
|
||||
size: {
|
||||
'50': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X50,
|
||||
},
|
||||
},
|
||||
'100': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X100,
|
||||
},
|
||||
},
|
||||
'200': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X200,
|
||||
},
|
||||
},
|
||||
'300': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X300,
|
||||
},
|
||||
},
|
||||
'400': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X400,
|
||||
},
|
||||
},
|
||||
'500': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X500,
|
||||
},
|
||||
},
|
||||
'600': {
|
||||
vars: {
|
||||
[PowerIconSize]: config.size.X600,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: '400',
|
||||
},
|
||||
});
|
||||
|
||||
export type PowerIconVariants = RecipeVariants<typeof PowerIcon>;
|
||||
Loading…
Add table
Add a link
Reference in a new issue