mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-06-16 09:39:09 +00:00
add databinding for editor actions and message
This commit is contained in:
parent
67fac31ab4
commit
b0c8b2378b
7 changed files with 57 additions and 16 deletions
|
@ -94,18 +94,27 @@ const StyledTextarea = styled.textarea`
|
||||||
export const MultilineTextInput = (
|
export const MultilineTextInput = (
|
||||||
props: TextInputProps<HTMLTextAreaElement> & { rows?: number }
|
props: TextInputProps<HTMLTextAreaElement> & { rows?: number }
|
||||||
) => {
|
) => {
|
||||||
const { ...rest } = props;
|
const { children, ...rest } = props;
|
||||||
const [value, setValue] = React.useState(String(props.value));
|
const [value, setValue] = React.useState(String(props.value));
|
||||||
const rows = Math.min(10, Math.max(props.rows || 2, value.split(/\r?\n/).length));
|
const rows = React.useMemo(
|
||||||
|
() => Math.min(10, Math.max(props.rows || 2, value.split(/\r?\n/).length)),
|
||||||
|
[value]
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setValue(String(props.value));
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTextarea
|
<StyledTextarea
|
||||||
{...rest}
|
{...rest}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
value={value}
|
|
||||||
onChange={(eventData) => {
|
onChange={(eventData) => {
|
||||||
setValue(eventData.target.value);
|
setValue(eventData.target.value);
|
||||||
props.onChange?.(eventData);
|
props.onChange?.(eventData);
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
{value}
|
||||||
|
</StyledTextarea>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { palette } from '@roleypoly/design-system/atoms/colors';
|
||||||
import { fontCSS } from '@roleypoly/design-system/atoms/fonts';
|
import { fontCSS } from '@roleypoly/design-system/atoms/fonts';
|
||||||
import styled, { createGlobalStyle } from 'styled-components';
|
import styled, { createGlobalStyle } from 'styled-components';
|
||||||
|
|
||||||
export const Content = styled.div<{ small?: boolean }>`
|
export const Content = styled.div<{ small?: boolean; double?: boolean }>`
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
margin-top: 50px;
|
margin-top: ${(props) => (props.double ? '100px' : '50px')};
|
||||||
width: ${(props) => (props.small ? '960px' : '1024px')};
|
width: ${(props) => (props.small ? '960px' : '1024px')};
|
||||||
max-width: 98vw;
|
max-width: 98vw;
|
||||||
max-height: calc(100vh - 50px);
|
max-height: calc(100vh - 50px);
|
||||||
|
|
|
@ -11,6 +11,7 @@ export type AppShellProps = {
|
||||||
user?: DiscordUser;
|
user?: DiscordUser;
|
||||||
showFooter?: boolean;
|
showFooter?: boolean;
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
|
double?: boolean;
|
||||||
activeGuildId?: string | null;
|
activeGuildId?: string | null;
|
||||||
guilds?: GuildSlug[];
|
guilds?: GuildSlug[];
|
||||||
recentGuilds?: string[];
|
recentGuilds?: string[];
|
||||||
|
@ -56,7 +57,9 @@ export const AppShell = (props: AppShellProps) => (
|
||||||
)}
|
)}
|
||||||
<OptionallyScroll shouldScroll={!props.skeleton}>
|
<OptionallyScroll shouldScroll={!props.skeleton}>
|
||||||
<>
|
<>
|
||||||
<Content small={props.small}>{props.children}</Content>
|
<Content small={props.small} double={props.double}>
|
||||||
|
{props.children}
|
||||||
|
</Content>
|
||||||
{props.showFooter && <Footer />}
|
{props.showFooter && <Footer />}
|
||||||
</>
|
</>
|
||||||
</OptionallyScroll>
|
</OptionallyScroll>
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
|
import { palette } from '@roleypoly/design-system/atoms/colors';
|
||||||
|
import { FaderOpacity } from '@roleypoly/design-system/atoms/fader';
|
||||||
import { Space } from '@roleypoly/design-system/atoms/space';
|
import { Space } from '@roleypoly/design-system/atoms/space';
|
||||||
|
import { MultilineTextInput } from '@roleypoly/design-system/atoms/text-input';
|
||||||
|
import { AmbientLarge, LargeText } from '@roleypoly/design-system/atoms/typography';
|
||||||
import { PickerCategory } from '@roleypoly/design-system/molecules/picker-category';
|
import { PickerCategory } from '@roleypoly/design-system/molecules/picker-category';
|
||||||
import { ServerMasthead } from '@roleypoly/design-system/molecules/server-masthead';
|
import { ServerMasthead } from '@roleypoly/design-system/molecules/server-masthead';
|
||||||
import { SecondaryEditing } from '@roleypoly/design-system/organisms/masthead';
|
import { SecondaryEditing } from '@roleypoly/design-system/organisms/masthead';
|
||||||
|
@ -7,11 +11,11 @@ import {
|
||||||
Container,
|
Container,
|
||||||
MessageBox,
|
MessageBox,
|
||||||
} from '@roleypoly/design-system/organisms/role-picker/RolePicker.styled';
|
} from '@roleypoly/design-system/organisms/role-picker/RolePicker.styled';
|
||||||
import { ReactifyNewlines } from '@roleypoly/misc-utils/ReactifyNewlines';
|
|
||||||
import { Category, CategoryType, PresentableGuild, Role } from '@roleypoly/types';
|
import { Category, CategoryType, PresentableGuild, Role } from '@roleypoly/types';
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
import { sortBy } from 'lodash';
|
import { sortBy } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { GoEyeClosed } from 'react-icons/go';
|
||||||
|
|
||||||
export type EditorShellProps = {
|
export type EditorShellProps = {
|
||||||
guild: PresentableGuild;
|
guild: PresentableGuild;
|
||||||
|
@ -23,6 +27,10 @@ export type EditorShellProps = {
|
||||||
export const EditorShell = (props: EditorShellProps) => {
|
export const EditorShell = (props: EditorShellProps) => {
|
||||||
const [guild, setGuild] = React.useState<PresentableGuild>(props.guild);
|
const [guild, setGuild] = React.useState<PresentableGuild>(props.guild);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setGuild(props.guild);
|
||||||
|
}, [props.guild]);
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
setGuild(props.guild);
|
setGuild(props.guild);
|
||||||
};
|
};
|
||||||
|
@ -50,14 +58,33 @@ export const EditorShell = (props: EditorShellProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SecondaryEditing showReset={hasChanges} guild={props.guild.guild} />
|
<SecondaryEditing
|
||||||
<Container style={{ marginTop: 90 }}>
|
showReset={hasChanges}
|
||||||
<Space />
|
guild={props.guild.guild}
|
||||||
|
onReset={reset}
|
||||||
|
onSubmit={() => props.onGuildChange?.(guild)}
|
||||||
|
/>
|
||||||
|
<Container style={{ marginTop: 95 }}>
|
||||||
<ServerMasthead guild={props.guild.guild} editable={false} />
|
<ServerMasthead guild={props.guild.guild} editable={false} />
|
||||||
<Space />
|
<Space />
|
||||||
|
|
||||||
<MessageBox>
|
<MessageBox>
|
||||||
<ReactifyNewlines>{props.guild.data.message}</ReactifyNewlines>
|
<LargeText>Server Message</LargeText>
|
||||||
|
<MultilineTextInput
|
||||||
|
rows={2}
|
||||||
|
value={guild.data.message}
|
||||||
|
onChange={(event) => onMessageChange(event.target.value)}
|
||||||
|
placeholder={`Hey friend from ${guild.guild.name}! Pick your roles!`}
|
||||||
|
>
|
||||||
|
{guild.data.message}
|
||||||
|
</MultilineTextInput>
|
||||||
|
<AmbientLarge style={{ display: 'flex', color: palette.taupe600 }}>
|
||||||
|
Shows a message to your server members.
|
||||||
|
<FaderOpacity isVisible={guild.data.message.trim().length === 0}>
|
||||||
|
Since the message is empty, this won't show up.
|
||||||
|
<GoEyeClosed style={{ position: 'relative', top: 2 }} />
|
||||||
|
</FaderOpacity>
|
||||||
|
</AmbientLarge>
|
||||||
</MessageBox>
|
</MessageBox>
|
||||||
<Space />
|
<Space />
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ export const SecondaryBase = styled(MastheadBase)`
|
||||||
background-color: ${palette.taupe300};
|
background-color: ${palette.taupe300};
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
|
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.05);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const IconHolder = styled.div`
|
export const IconHolder = styled.div`
|
||||||
|
|
|
@ -15,6 +15,8 @@ import {
|
||||||
type SecondaryEditingProps = {
|
type SecondaryEditingProps = {
|
||||||
guild: GuildSlug;
|
guild: GuildSlug;
|
||||||
showReset: boolean;
|
showReset: boolean;
|
||||||
|
onReset?: () => void;
|
||||||
|
onSubmit?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SecondaryEditing = (props: SecondaryEditingProps) => (
|
export const SecondaryEditing = (props: SecondaryEditingProps) => (
|
||||||
|
@ -30,12 +32,12 @@ export const SecondaryEditing = (props: SecondaryEditingProps) => (
|
||||||
</MastheadLeft>
|
</MastheadLeft>
|
||||||
<MastheadRight>
|
<MastheadRight>
|
||||||
<FaderOpacity isVisible={props.showReset}>
|
<FaderOpacity isVisible={props.showReset}>
|
||||||
<Button size="small" color="silent">
|
<Button size="small" color="silent" onClick={props.onReset}>
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
</FaderOpacity>
|
</FaderOpacity>
|
||||||
|
|
||||||
<Button size="small">
|
<Button size="small" onClick={props.onSubmit}>
|
||||||
Done <GoCheck />
|
Done <GoCheck />
|
||||||
</Button>
|
</Button>
|
||||||
</MastheadRight>
|
</MastheadRight>
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const EditorTemplate = (
|
||||||
const { guild, onCategoryChange, onMessageChange, onGuildChange, ...appShellProps } =
|
const { guild, onCategoryChange, onMessageChange, onGuildChange, ...appShellProps } =
|
||||||
props;
|
props;
|
||||||
return (
|
return (
|
||||||
<AppShell {...appShellProps} activeGuildId={guild.id}>
|
<AppShell {...appShellProps} activeGuildId={guild.id} small double>
|
||||||
<EditorShell guild={guild} onGuildChange={onGuildChange} />
|
<EditorShell guild={guild} onGuildChange={onGuildChange} />
|
||||||
</AppShell>
|
</AppShell>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue