intermediate commit
This commit is contained in:
parent
4b9052a3c5
commit
b20943213c
@ -1,6 +1,6 @@
|
||||
import React, { FC, Ref, useCallback, useMemo } from 'react';
|
||||
|
||||
export enum ButtonType {
|
||||
export enum ButtonColorType {
|
||||
BRAND = '',
|
||||
POSITIVE = 'positive',
|
||||
NEGATIVE = 'negative',
|
||||
@ -10,26 +10,27 @@ export enum ButtonType {
|
||||
interface ButtonProps {
|
||||
ref?: Ref<HTMLDivElement>;
|
||||
|
||||
type?: ButtonType;
|
||||
colorType?: ButtonColorType;
|
||||
|
||||
onClick?: () => void;
|
||||
shaking?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const DefaultButtonProps: ButtonProps = {
|
||||
type: ButtonType.BRAND
|
||||
const DefaultButtonProps = {
|
||||
colorType: ButtonColorType.BRAND,
|
||||
}
|
||||
|
||||
const Button: FC<ButtonProps> = React.forwardRef((props: ButtonProps, ref: Ref<HTMLDivElement>) => {
|
||||
const { type, onClick, shaking, children } = { ...DefaultButtonProps, ...props };
|
||||
const { colorType, onClick, shaking, children } = { ...DefaultButtonProps, ...props };
|
||||
|
||||
const className = useMemo(
|
||||
() => [
|
||||
'button',
|
||||
type,
|
||||
colorType,
|
||||
shaking && 'shaking-horizontal',
|
||||
].filter(c => typeof c === 'string').join(' '),
|
||||
[ type, shaking ]
|
||||
[ colorType, shaking ]
|
||||
);
|
||||
|
||||
const clickHandler = useCallback(() => {
|
||||
|
@ -5,7 +5,7 @@ const LOG = Logger.create(__filename, electronConsole);
|
||||
|
||||
import React, { FC, useEffect, useMemo, useState } from "react";
|
||||
import ElementsUtil from "../require/elements-util";
|
||||
import Button, { ButtonType } from "./button";
|
||||
import Button, { ButtonColorType } from "./button";
|
||||
import DisplayPopup from "./display-popup";
|
||||
|
||||
interface DisplayProps {
|
||||
@ -53,20 +53,20 @@ const Display: FC<DisplayProps> = (props: DisplayProps) => {
|
||||
if (errorMessage) {
|
||||
return (
|
||||
<DisplayPopup tip={errorMessage}>
|
||||
<Button type={ButtonType.PERDU} onClick={resetChanges}>Reset</Button>
|
||||
<Button colorType={ButtonColorType.PERDU} onClick={resetChanges}>Reset</Button>
|
||||
</DisplayPopup>
|
||||
);
|
||||
} else if (infoMessage && infoMessage !== dismissedInfoMessage) {
|
||||
return (
|
||||
<DisplayPopup tip={infoMessage}>
|
||||
<Button type={ButtonType.PERDU} onClick={dismissInfoMessage}>X</Button>
|
||||
<Button colorType={ButtonColorType.PERDU} onClick={dismissInfoMessage}>X</Button>
|
||||
</DisplayPopup>
|
||||
);
|
||||
} else if (changes) {
|
||||
return (
|
||||
<DisplayPopup tip="You have unsaved changes">
|
||||
<Button type={ButtonType.PERDU} onClick={resetChanges}>Reset</Button>
|
||||
<Button type={ButtonType.POSITIVE} onClick={saveChanges} shaking={saveButtonShaking}>{changesButtonText}</Button>
|
||||
<Button colorType={ButtonColorType.PERDU} onClick={resetChanges}>Reset</Button>
|
||||
<Button colorType={ButtonColorType.POSITIVE} onClick={saveChanges} shaking={saveButtonShaking}>{changesButtonText}</Button>
|
||||
</DisplayPopup>
|
||||
);
|
||||
} else {
|
||||
|
@ -1,28 +1,75 @@
|
||||
import React, { ChangeEvent, createRef, FC, useMemo } from 'react';
|
||||
import React, { ChangeEvent, createRef, FC, MouseEvent, MouseEventHandler, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
export interface DropdownInputProps {
|
||||
label?: string;
|
||||
options: { value: string, display: string }[];
|
||||
width?: number;
|
||||
value: string;
|
||||
setValue: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
|
||||
const DefaultDropdownInputProps = {
|
||||
width: 150
|
||||
}
|
||||
|
||||
const DropdownInput: FC<DropdownInputProps> = (props: DropdownInputProps) => {
|
||||
const { options, value, setValue } = props;
|
||||
const { label, options, width, value, setValue } = { ...DefaultDropdownInputProps, ...props };
|
||||
|
||||
// A dropdown input that mimicks the "select" input
|
||||
// Supports mouse-click selects
|
||||
// TODO: Has a \/ dropdown indicator
|
||||
// TODO: Supports up+down arrows to change input (both while dropdown is active and when closed)
|
||||
// TODO: Supports max dropdown size + scrolling dropdown
|
||||
// TODO: Supports opening above if at the bottom of a page
|
||||
|
||||
const displayRef = createRef<HTMLDivElement>();
|
||||
|
||||
const [ display, setDisplay ] = useState<string>('');
|
||||
const [ optionsOpen, setOptionsOpen ] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
// only do this expensive version once
|
||||
setDisplay(options.find(option => option.value === value)?.display ?? '');
|
||||
}, []);
|
||||
|
||||
const optionElements = useMemo(() => {
|
||||
return options.map(option => {
|
||||
return <option key={option.value} value={option.value}>{option.display}</option>
|
||||
const className = option.value === value ? 'option selected' : 'option';
|
||||
const onClick = () => {
|
||||
setValue(option.value);
|
||||
setDisplay(option.display);
|
||||
setOptionsOpen(false);
|
||||
}
|
||||
return <div className={className} key={option.value} onClick={onClick}>{option.display}</div>
|
||||
});
|
||||
}, [ options ]);
|
||||
|
||||
const onChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
setValue(e.target.value);
|
||||
}
|
||||
const labelElement = useMemo(() => {
|
||||
return label && <div className="label">{label}</div>
|
||||
}, [ label ]);
|
||||
|
||||
const onDisplayClick = useCallback((e: MouseEvent) => {
|
||||
if (e.target !== displayRef.current) return;
|
||||
setOptionsOpen(prev => !prev);
|
||||
}, [ displayRef ]);
|
||||
|
||||
const onMainBlur = useCallback(() => {
|
||||
setOptionsOpen(false);
|
||||
}, []);
|
||||
|
||||
const optionsClassName = useMemo(() => optionsOpen ? 'options open' : 'options', [ optionsOpen ]);
|
||||
|
||||
return (
|
||||
<div className="dropdown-react">
|
||||
<select onChange={onChange} value={value}>
|
||||
<div className="dropdown-react" tabIndex={0} onBlur={onMainBlur}>
|
||||
{labelElement}
|
||||
<div
|
||||
ref={displayRef} className="display"
|
||||
onClick={onDisplayClick}
|
||||
style={{ width: width }}
|
||||
>{display}</div>
|
||||
<div className={optionsClassName}>
|
||||
{optionElements}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -8,11 +8,9 @@ import React, { FC, Ref, useEffect, useMemo } from 'react';
|
||||
export interface TextInputProps {
|
||||
ref?: Ref<HTMLInputElement>;
|
||||
|
||||
label: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
|
||||
noLabel?: boolean;
|
||||
|
||||
allowEmpty?: boolean;
|
||||
maxLength: number;
|
||||
|
||||
@ -27,7 +25,7 @@ export interface TextInputProps {
|
||||
}
|
||||
|
||||
const TextInput: FC<TextInputProps> = React.forwardRef((props: TextInputProps, ref: Ref<HTMLInputElement>) => {
|
||||
const { label, placeholder, noLabel, allowEmpty, maxLength, value, setValue, setValid, setMessage, onEnterKeyDown, valueMap } = props;
|
||||
const { label, placeholder, allowEmpty, maxLength, value, setValue, setValid, setMessage, onEnterKeyDown, valueMap } = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (maxLength !== undefined && value.length > maxLength) {
|
||||
@ -45,7 +43,7 @@ const TextInput: FC<TextInputProps> = React.forwardRef((props: TextInputProps, r
|
||||
}, [ value ]);
|
||||
|
||||
const labelElement = useMemo(() => {
|
||||
return label && !noLabel && <div className="label">{label}</div>
|
||||
return label && <div className="label">{label}</div>
|
||||
}, [ label ]);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
39
src/client/webapp/elements/components/table-invites.tsx
Normal file
39
src/client/webapp/elements/components/table-invites.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import moment from 'moment';
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import { Token } from '../../data-types';
|
||||
import CombinedGuild from '../../guild-combined';
|
||||
import Button, { ButtonColorType } from './button';
|
||||
import Table from './table';
|
||||
|
||||
export interface InvitesTableProps {
|
||||
guild: CombinedGuild
|
||||
}
|
||||
|
||||
const InvitesTable: FC<InvitesTableProps> = (props: InvitesTableProps) => {
|
||||
const { guild } = props;
|
||||
|
||||
const fetchData = useCallback(async () => await guild.fetchTokens(), [ guild ]);
|
||||
const header = (
|
||||
<tr>
|
||||
<th>Created</th>
|
||||
<th>Expires</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
);
|
||||
const mapToRow = useCallback((token: Token) => {
|
||||
return (
|
||||
<tr key={token.token}>
|
||||
<td>{moment(token.created).fromNow()}</td>
|
||||
<td>{moment(token.expires).fromNow()}</td>
|
||||
<td className="actions">
|
||||
<Button colorType={ButtonColorType.POSITIVE}>Save</Button>
|
||||
<Button colorType={ButtonColorType.NEGATIVE}>Delete</Button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}, []);
|
||||
|
||||
return <Table header={header} fetchData={fetchData} mapToRow={mapToRow} />
|
||||
}
|
||||
|
||||
export default InvitesTable;
|
43
src/client/webapp/elements/components/table.tsx
Normal file
43
src/client/webapp/elements/components/table.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import * as electronRemote from '@electron/remote';
|
||||
const electronConsole = electronRemote.getGlobal('console') as Console;
|
||||
import Logger from '../../../../logger/logger';
|
||||
const LOG = Logger.create(__filename, electronConsole);
|
||||
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
|
||||
export interface TableProps<T> {
|
||||
header: JSX.Element;
|
||||
fetchData: () => Promise<T[]>;
|
||||
mapToRow: (data: T) => JSX.Element;
|
||||
}
|
||||
|
||||
export default function Table<T>(props: TableProps<T>) {
|
||||
const { header, fetchData, mapToRow } = props;
|
||||
|
||||
// TODO: Loading indicator + fetch failed indicator
|
||||
|
||||
const [ dataRows, setDataRows ] = useState<JSX.Element[]>([]);
|
||||
const [ loading, setLoading ] = useState<boolean>(true);
|
||||
const [ fetchFailed, setFetchFailed ] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchData();
|
||||
setDataRows(data.map(mapToRow));
|
||||
} catch (e: unknown) {
|
||||
LOG.error('error fetching data for table', e);
|
||||
setFetchFailed(true);
|
||||
}
|
||||
setLoading(false);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<table>
|
||||
<thead>{header}</thead>
|
||||
<tbody>{dataRows}</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
@ -13,6 +13,8 @@ import ReactHelper from '../require/react-helper';
|
||||
import { Duration } from 'moment';
|
||||
import moment from 'moment';
|
||||
import DropdownInput from '../components/input-dropdown';
|
||||
import Button from '../components/button';
|
||||
import InvitesTable from '../components/table-invites';
|
||||
|
||||
|
||||
export interface GuildInvitesDisplayProps {
|
||||
@ -33,16 +35,6 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
|
||||
|
||||
const [ guildMetaFailed, setGuildMetaFailed ] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (expiresFromNowText === 'never') {
|
||||
setExpiresFromNow(null);
|
||||
return;
|
||||
} else {
|
||||
const splt = expiresFromNowText.split(' ');
|
||||
setExpiresFromNow(moment.duration(splt[0], splt[1] as moment.unitOfTime.DurationConstructor));
|
||||
}
|
||||
}, [ expiresFromNowText ]);
|
||||
|
||||
ReactHelper.useGuildMetadataEffect({
|
||||
guild,
|
||||
onSuccess: (guildMeta: GuildMetadata) => {
|
||||
@ -57,6 +49,16 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
|
||||
onSuccess: setIconSrc
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (expiresFromNowText === 'never') {
|
||||
setExpiresFromNow(null);
|
||||
return;
|
||||
} else {
|
||||
const splt = expiresFromNowText.split(' ');
|
||||
setExpiresFromNow(moment.duration(splt[0], splt[1] as moment.unitOfTime.DurationConstructor));
|
||||
}
|
||||
}, [ expiresFromNowText ]);
|
||||
|
||||
const errorMessage = useMemo(() => {
|
||||
if (guildMetaFailed) return 'Unable to load guild metadata';
|
||||
return null;
|
||||
@ -66,21 +68,30 @@ const GuildInvitesDisplay: FC<GuildInvitesDisplayProps> = (props: GuildInvitesDi
|
||||
<Display
|
||||
infoMessage={null} errorMessage={errorMessage}
|
||||
>
|
||||
<div className="section-title">Create Invite</div>
|
||||
<div className="create-invite">
|
||||
<div className="actions">
|
||||
<DropdownInput value={expiresFromNowText} setValue={setExpiresFromNowText} options={[
|
||||
{ value: '1 day', display: 'Expires in 1 Day' },
|
||||
{ value: '1 week', display: 'Expires in 1 Week' },
|
||||
{ value: '1 month', display: 'Expires in 1 Month' },
|
||||
{ value: '1 year', display: 'Expires in 1 Year' },
|
||||
{ value: 'never', display: 'Never expires' },
|
||||
]} />
|
||||
<div className="invites">
|
||||
<div className="create-invite">
|
||||
<div className="title">Create Invite</div>
|
||||
<div className="interface">
|
||||
<div className="inputs">
|
||||
<DropdownInput label="Expires In" value={expiresFromNowText} setValue={setExpiresFromNowText} options={[
|
||||
{ value: '1 day', display: 'a Day' },
|
||||
{ value: '1 week', display: 'a Week' },
|
||||
{ value: '1 month', display: 'a Month' },
|
||||
{ value: 'never', display: 'Never' },
|
||||
]} />
|
||||
<div><Button>Create Invite</Button></div>
|
||||
</div>
|
||||
<InvitePreview
|
||||
name={guildName ?? ''} iconSrc={iconSrc}
|
||||
url={url} expiresFromNow={expiresFromNow}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="divider" />
|
||||
<div className="view-invites">
|
||||
<div className="title">Active Invites</div>
|
||||
<InvitesTable guild={guild} />
|
||||
</div>
|
||||
<InvitePreview
|
||||
name={guildName ?? ''} iconSrc={iconSrc}
|
||||
url={url} expiresFromNow={expiresFromNow}
|
||||
/>
|
||||
</div>
|
||||
</Display>
|
||||
)
|
||||
|
@ -15,10 +15,10 @@ import ReactHelper from '../require/react-helper';
|
||||
|
||||
export interface GuildOverviewDisplayProps {
|
||||
guild: CombinedGuild;
|
||||
setGuildName: React.Dispatch<React.SetStateAction<string>>; // to allow overlay title to update
|
||||
setContainerGuildName: React.Dispatch<React.SetStateAction<string>>; // to allow overlay title to update
|
||||
}
|
||||
const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOverviewDisplayProps) => {
|
||||
const { guild } = props;
|
||||
const { guild, setContainerGuildName } = props;
|
||||
|
||||
const [ iconResourceId, setIconResourceId ] = useState<string | null>(null);
|
||||
|
||||
@ -43,11 +43,15 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
|
||||
ReactHelper.useGuildMetadataEffect({
|
||||
guild,
|
||||
onSuccess: (guildMeta: GuildMetadata) => {
|
||||
setContainerGuildName(guildMeta.name);
|
||||
setSavedName(guildMeta.name);
|
||||
setName(guildMeta.name);
|
||||
setIconResourceId(guildMeta.iconResourceId);
|
||||
},
|
||||
onError: () => setGuildMetaFailed(true)
|
||||
onError: () => {
|
||||
setGuildMetaFailed(true);
|
||||
setContainerGuildName('<unknown>');
|
||||
}
|
||||
})
|
||||
|
||||
ReactHelper.useNullableResourceEffect({
|
||||
@ -95,6 +99,7 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
|
||||
// Save name
|
||||
try {
|
||||
await guild.requestSetGuildName(name);
|
||||
setContainerGuildName(name);
|
||||
setSavedName(name);
|
||||
} catch (e: unknown) {
|
||||
LOG.error('error setting guild name', e);
|
||||
@ -128,21 +133,23 @@ const GuildOverviewDisplay: FC<GuildOverviewDisplayProps> = (props: GuildOvervie
|
||||
saving={saving} saveFailed={saveFailed}
|
||||
errorMessage={errorMessage} infoMessage={infoMessage}
|
||||
>
|
||||
<div className="metadata">
|
||||
<div className="icon">
|
||||
<ImageEditInput
|
||||
maxSize={Globals.MAX_GUILD_ICON_SIZE} value={iconBuff} setValue={setIconBuff}
|
||||
setValid={setIconInputValid} setMessage={setIconInputMessage}
|
||||
/>
|
||||
</div>
|
||||
<div className="name">
|
||||
<TextInput
|
||||
label={'Guild Name'} placeholder={savedName ?? 'Guild Name'}
|
||||
maxLength={Globals.MAX_GUILD_NAME_LENGTH}
|
||||
value={name ?? ''} setValue={setName as Dispatch<SetStateAction<string>>}
|
||||
setValid={setNameInputValid} setMessage={setNameInputMessage}
|
||||
onEnterKeyDown={saveChanges}
|
||||
/>
|
||||
<div className="overview">
|
||||
<div className="metadata">
|
||||
<div className="icon">
|
||||
<ImageEditInput
|
||||
maxSize={Globals.MAX_GUILD_ICON_SIZE} value={iconBuff} setValue={setIconBuff}
|
||||
setValid={setIconInputValid} setMessage={setIconInputMessage}
|
||||
/>
|
||||
</div>
|
||||
<div className="name">
|
||||
<TextInput
|
||||
label={'Guild Name'} placeholder={savedName ?? 'Guild Name'}
|
||||
maxLength={Globals.MAX_GUILD_NAME_LENGTH}
|
||||
value={name ?? ''} setValue={setName as Dispatch<SetStateAction<string>>}
|
||||
setValid={setNameInputValid} setMessage={setNameInputMessage}
|
||||
onEnterKeyDown={saveChanges}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Display>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { FC, useEffect, useState } from "react";
|
||||
import { GuildMetadata } from "../../data-types";
|
||||
import CombinedGuild from "../../guild-combined";
|
||||
import ChoicesControl from "../components/control-choices";
|
||||
import GuildInvitesDisplay from "../displays/display-guild-invites";
|
||||
@ -17,7 +16,7 @@ const GuildSettingsOverlay: FC<GuildSettingsOverlayProps> = (props: GuildSetting
|
||||
const [ display, setDisplay ] = useState<JSX.Element>();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedId === 'overview') setDisplay(<GuildOverviewDisplay guild={guild} setGuildName={setGuildName} />);
|
||||
if (selectedId === 'overview') setDisplay(<GuildOverviewDisplay guild={guild} setContainerGuildName={setGuildName} />);
|
||||
//if (selectedId === 'channels') setDisplay(<GuildOverviewDisplay guild={guild} guildMeta={guildMeta} />);
|
||||
//if (selectedId === 'roles' ) setDisplay(<GuildOverviewDisplay guild={guild} guildMeta={guildMeta} />);
|
||||
if (selectedId === 'invites' ) setDisplay(<GuildInvitesDisplay guild={guild} />);
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
/* Buttons */
|
||||
.button {
|
||||
display: inline-block;
|
||||
background-color: $brand;
|
||||
color: $header-primary;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
padding: 8px 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: $brand-hover;
|
||||
@ -23,7 +24,7 @@
|
||||
&.negative {
|
||||
background-color: $background-button-negative;
|
||||
|
||||
&:negative {
|
||||
&:hover {
|
||||
background-color: $background-button-negative-hover;
|
||||
}
|
||||
}
|
||||
@ -35,4 +36,16 @@
|
||||
background-color: $background-button-perdu-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&.lower-submit {
|
||||
padding: 8px 24px;
|
||||
}
|
||||
|
||||
&.display-popup {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
&.table-icon {
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,60 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-react {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.label {
|
||||
font-size: 0.75em;
|
||||
font-weight: bold;
|
||||
color: $interactive-normal;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.display {
|
||||
background-color: $background-input;
|
||||
color: $text-normal;
|
||||
padding: 8px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
border: 1px solid $border-input;
|
||||
}
|
||||
|
||||
&:hover .display {
|
||||
border-color: $border-input-hover;
|
||||
}
|
||||
|
||||
&:focus .display {
|
||||
border-color: $border-input-focus;
|
||||
}
|
||||
|
||||
.options {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:not(.open) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 8px;
|
||||
color: $text-normal;
|
||||
background-color: $background-dropdown-option;
|
||||
|
||||
&:hover {
|
||||
background-color: $background-dropdown-option-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.display {
|
||||
$content-border-radius: 4px;
|
||||
|
||||
@ -76,6 +130,12 @@
|
||||
|
||||
> .scroll {
|
||||
margin: 32px;
|
||||
|
||||
.divider {
|
||||
margin: 24px 0;
|
||||
height: 1px;
|
||||
background-color: $background-primary-divider;
|
||||
}
|
||||
}
|
||||
|
||||
> .popup {
|
||||
|
@ -303,30 +303,72 @@ body > .overlay,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.display {
|
||||
.title {
|
||||
font-weight: 600;
|
||||
color: $text-normal;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* guild Settings Overlay */
|
||||
/* guild Settings Overlay*/
|
||||
|
||||
> .content.display-swapper.guild-settings {
|
||||
min-width: 350px;
|
||||
|
||||
.metadata {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.name {
|
||||
margin-left: 16px;
|
||||
}
|
||||
.overview {
|
||||
.metadata {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.guild-name.text-input {
|
||||
color: $header-primary;
|
||||
font-weight: 500;
|
||||
width: 150px;
|
||||
.name {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.guild-name.text-input {
|
||||
color: $header-primary;
|
||||
font-weight: 500;
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button.metadata-submit {
|
||||
display: inline-block;
|
||||
.invites {
|
||||
.create-invite {
|
||||
.interface {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.inputs > :not(:last-child) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.guild-preview {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.view-invites {
|
||||
color: $text-normal;
|
||||
|
||||
th {
|
||||
text-transform: uppercase;
|
||||
text-align: left;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
td.actions {
|
||||
display: flex;
|
||||
|
||||
:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,16 @@ $background-message-hover: rgba(4, 4, 5, 0.07);
|
||||
$background-overlay: rgba(12, 13, 14, 0.75);
|
||||
$background-popup-message: rgba(30, 31, 34, 0.75);
|
||||
|
||||
$background-primary-divider: #3f4149;
|
||||
|
||||
$background-input: #2f3136;
|
||||
$border-input: #1d1e22;
|
||||
$border-input-hover: #0b0c0e;
|
||||
$border-input-focus: #0099ff;
|
||||
|
||||
$background-dropdown-option: #272a2e;
|
||||
$background-dropdown-option-hover: #1a1c1f;
|
||||
|
||||
$channels-default: #8e9297;
|
||||
$channeltextarea-background: #40444b;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user