forked from abner/for-legacy-web
feat(@ui): migrate category / overline and header
This commit is contained in:
@@ -5,16 +5,17 @@ import { useTriggerEvents } from "preact-context-menu";
|
||||
import { memo } from "preact/compat";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
import { Category } from "@revoltchat/ui";
|
||||
|
||||
import { internalEmit } from "../../../lib/eventEmitter";
|
||||
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
|
||||
|
||||
import { QueuedMessage } from "../../../mobx/stores/MessageQueue";
|
||||
|
||||
import { I18nError } from "../../../context/Locale";
|
||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||
import { useClient } from "../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import Overline from "../../ui/Overline";
|
||||
|
||||
import { Children } from "../../../types/Preact";
|
||||
import Markdown from "../../markdown/Markdown";
|
||||
import UserIcon from "../user/UserIcon";
|
||||
@@ -162,7 +163,9 @@ const Message = observer(
|
||||
{replacement ?? <Markdown content={content} />}
|
||||
{!queued && <InviteList message={message} />}
|
||||
{queued?.error && (
|
||||
<Overline type="error" error={queued.error} />
|
||||
<Category>
|
||||
<I18nError error={queued.error} />
|
||||
</Category>
|
||||
)}
|
||||
{message.attachments?.map((attachment, index) => (
|
||||
<Attachment
|
||||
|
||||
@@ -7,10 +7,11 @@ import styled, { css } from "styled-components/macro";
|
||||
|
||||
import { useContext, useEffect, useState } from "preact/hooks";
|
||||
|
||||
import { Button, Preloader } from "@revoltchat/ui";
|
||||
import { Button, Category, Preloader } from "@revoltchat/ui";
|
||||
|
||||
import { isTouchscreenDevice } from "../../../../lib/isTouchscreenDevice";
|
||||
|
||||
import { I18nError } from "../../../../context/Locale";
|
||||
import {
|
||||
AppContext,
|
||||
ClientStatus,
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
import { takeError } from "../../../../context/revoltjs/util";
|
||||
|
||||
import ServerIcon from "../../../../components/common/ServerIcon";
|
||||
import Overline from "../../../ui/Overline";
|
||||
|
||||
const EmbedInviteBase = styled.div`
|
||||
width: 400px;
|
||||
@@ -159,7 +159,11 @@ export function EmbedInvite({ code }: Props) {
|
||||
</Button>
|
||||
)}
|
||||
</EmbedInviteBase>
|
||||
{joinError && <Overline type="error" error={joinError} />}
|
||||
{joinError && (
|
||||
<Category>
|
||||
<I18nError error={joinError} />
|
||||
</Category>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,12 @@ import styled from "styled-components/macro";
|
||||
import { openContextMenu } from "preact-context-menu";
|
||||
import { Text, Localizer } from "preact-i18n";
|
||||
|
||||
import { IconButton } from "@revoltchat/ui";
|
||||
import { Header, IconButton } from "@revoltchat/ui";
|
||||
|
||||
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
|
||||
|
||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||
|
||||
import Header from "../../ui/Header";
|
||||
import Tooltip from "../Tooltip";
|
||||
import UserStatus from "./UserStatus";
|
||||
|
||||
@@ -52,7 +51,7 @@ export default observer(({ user }: Props) => {
|
||||
const { writeClipboard } = useIntermediate();
|
||||
|
||||
return (
|
||||
<Header topBorder placement="secondary">
|
||||
<Header topBorder palette="secondary">
|
||||
<HeaderBase>
|
||||
<Localizer>
|
||||
<Tooltip content={<Text id="app.special.copy_username" />}>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Plus } from "@styled-icons/boxicons-regular";
|
||||
import {
|
||||
Home,
|
||||
UserDetail,
|
||||
@@ -11,6 +12,8 @@ import styled, { css } from "styled-components/macro";
|
||||
import { Text } from "preact-i18n";
|
||||
import { useContext, useEffect } from "preact/hooks";
|
||||
|
||||
import { Category, IconButton } from "@revoltchat/ui";
|
||||
|
||||
import ConditionalLink from "../../../lib/ConditionalLink";
|
||||
import PaintCounter from "../../../lib/PaintCounter";
|
||||
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
|
||||
@@ -20,7 +23,6 @@ import { useApplicationState } from "../../../mobx/State";
|
||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import Category from "../../ui/Category";
|
||||
import placeholderSVG from "../items/placeholder.svg";
|
||||
|
||||
import { GenericSidebarBase, GenericSidebarList } from "../SidebarBase";
|
||||
@@ -125,15 +127,18 @@ export default observer(() => {
|
||||
</ButtonItem>
|
||||
</Link>
|
||||
)}
|
||||
<Category
|
||||
text={<Text id="app.main.categories.conversations" />}
|
||||
action={() =>
|
||||
openScreen({
|
||||
id: "special_input",
|
||||
type: "create_group",
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Category>
|
||||
<Text id="app.main.categories.conversations" />
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
openScreen({
|
||||
id: "special_input",
|
||||
type: "create_group",
|
||||
})
|
||||
}>
|
||||
<Plus size={16} />
|
||||
</IconButton>
|
||||
</Category>
|
||||
{channels.length === 0 && (
|
||||
<img src={placeholderSVG} loading="eager" />
|
||||
)}
|
||||
|
||||
@@ -30,11 +30,14 @@ export default observer(() => {
|
||||
|
||||
return (
|
||||
<ServerList
|
||||
// @ts-expect-error FIXME
|
||||
client={client}
|
||||
active={server_id}
|
||||
createServer={createServer}
|
||||
// @ts-expect-error FIXME
|
||||
permit={state.notifications}
|
||||
home={state.layout.getLastHomePath}
|
||||
// @ts-expect-error FIXME
|
||||
servers={state.ordering.orderedServers}
|
||||
reorder={state.ordering.reorderServer}
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Redirect, useParams } from "react-router";
|
||||
import { Server } from "revolt.js";
|
||||
import styled, { css } from "styled-components/macro";
|
||||
|
||||
import { Ref } from "preact";
|
||||
import { useTriggerEvents } from "preact-context-menu";
|
||||
import { useEffect } from "preact/hooks";
|
||||
|
||||
import { Category } from "@revoltchat/ui";
|
||||
|
||||
import ConditionalLink from "../../../lib/ConditionalLink";
|
||||
import PaintCounter from "../../../lib/PaintCounter";
|
||||
import { internalEmit } from "../../../lib/eventEmitter";
|
||||
@@ -18,8 +18,6 @@ import { useClient } from "../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import CollapsibleSection from "../../common/CollapsibleSection";
|
||||
import ServerHeader from "../../common/ServerHeader";
|
||||
import Category from "../../ui/Category";
|
||||
|
||||
import { ChannelButton } from "../items/ButtonItem";
|
||||
import ConnectionStatus from "../items/ConnectionStatus";
|
||||
|
||||
@@ -126,7 +124,7 @@ export default observer(() => {
|
||||
<CollapsibleSection
|
||||
id={`category_${category.id}`}
|
||||
defaultValue
|
||||
summary={<Category text={category.title} />}>
|
||||
summary={<Category>{category.title}</Category>}>
|
||||
{channels}
|
||||
</CollapsibleSection>,
|
||||
);
|
||||
|
||||
@@ -5,12 +5,11 @@ import styled from "styled-components/macro";
|
||||
import { Text } from "preact-i18n";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
import { Button, InputBox, Preloader } from "@revoltchat/ui";
|
||||
import { Button, Category, Error, InputBox, Preloader } from "@revoltchat/ui";
|
||||
|
||||
import { useClient } from "../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import Message from "../../common/messaging/Message";
|
||||
import Overline from "../../ui/Overline";
|
||||
import { GenericSidebarBase, GenericSidebarList } from "../SidebarBase";
|
||||
|
||||
type SearchState =
|
||||
@@ -100,12 +99,14 @@ export function SearchSidebar({ close }: Props) {
|
||||
<GenericSidebarBase data-scroll-offset="with-padding">
|
||||
<GenericSidebarList>
|
||||
<SearchBase>
|
||||
<Overline type="accent" block hover>
|
||||
<a onClick={close}>« back to members</a>
|
||||
</Overline>
|
||||
<Overline type="subtle" block>
|
||||
<Category>
|
||||
<Error
|
||||
error={<a onClick={close}>« back to members</a>}
|
||||
/>
|
||||
</Category>
|
||||
<Category>
|
||||
<Text id="app.main.channel.search.title" />
|
||||
</Overline>
|
||||
</Category>
|
||||
<InputBox
|
||||
value={query}
|
||||
onKeyDown={(e) => e.key === "Enter" && search()}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { Plus } from "@styled-icons/boxicons-regular";
|
||||
import styled, { css } from "styled-components/macro";
|
||||
|
||||
import { Children } from "../../types/Preact";
|
||||
|
||||
const CategoryBase = styled.div<Pick<Props, "variant">>`
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
|
||||
margin-top: 4px;
|
||||
padding: 6px 0 6px 8px;
|
||||
margin-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.variant === "uniform" &&
|
||||
css`
|
||||
padding-top: 6px;
|
||||
`}
|
||||
`;
|
||||
|
||||
type Props = Omit<
|
||||
JSX.HTMLAttributes<HTMLDivElement>,
|
||||
"children" | "as" | "action"
|
||||
> & {
|
||||
text: Children;
|
||||
action?: () => void;
|
||||
variant?: "default" | "uniform";
|
||||
};
|
||||
|
||||
export default function Category(props: Props) {
|
||||
const { text, action, ...otherProps } = props;
|
||||
|
||||
return (
|
||||
<CategoryBase {...otherProps}>
|
||||
{text}
|
||||
{action && <Plus size={16} onClick={action} />}
|
||||
</CategoryBase>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { observer } from "mobx-react-lite";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import styled, { css } from "styled-components/macro";
|
||||
|
||||
import { Header } from "@revoltchat/ui";
|
||||
|
||||
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
|
||||
|
||||
import { useApplicationState } from "../../mobx/State";
|
||||
@@ -18,82 +20,11 @@ interface Props {
|
||||
topBorder?: boolean;
|
||||
bottomBorder?: boolean;
|
||||
|
||||
background?: boolean;
|
||||
transparent?: boolean;
|
||||
withBackground?: boolean;
|
||||
withTransparency?: boolean;
|
||||
placement: "primary" | "secondary";
|
||||
}
|
||||
|
||||
const Header = styled.div<Props>`
|
||||
gap: 10px;
|
||||
flex: 0 auto;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
padding: 0 16px;
|
||||
font-weight: 600;
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
|
||||
height: var(--header-height);
|
||||
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
margin-inline-end: 8px;
|
||||
color: var(--secondary-foreground);
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.transparent
|
||||
? css`
|
||||
background-color: rgba(
|
||||
var(--primary-header-rgb),
|
||||
max(var(--min-opacity), 0.75)
|
||||
);
|
||||
backdrop-filter: blur(20px);
|
||||
z-index: 20;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
`
|
||||
: css`
|
||||
background-color: var(--primary-header);
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.background &&
|
||||
css`
|
||||
height: 120px !important;
|
||||
align-items: flex-end;
|
||||
|
||||
text-shadow: 0px 0px 1px black;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.placement === "secondary" &&
|
||||
css`
|
||||
background-color: var(--secondary-header);
|
||||
padding: 14px;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.topBorder &&
|
||||
css`
|
||||
border-start-start-radius: 8px;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.bottomBorder &&
|
||||
css`
|
||||
border-end-start-radius: 8px;
|
||||
`}
|
||||
`;
|
||||
|
||||
export default Header;
|
||||
|
||||
const IconContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -128,7 +59,7 @@ export const PageHeader = observer(
|
||||
return (
|
||||
<Header
|
||||
{...props}
|
||||
placement="primary"
|
||||
palette="primary"
|
||||
topBorder={!visible}
|
||||
bottomBorder={!pathname.includes("/server")}>
|
||||
{!noBurger && <HamburgerAction />}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import styled, { css } from "styled-components/macro";
|
||||
|
||||
import { Text } from "preact-i18n";
|
||||
|
||||
import { Children } from "../../types/Preact";
|
||||
|
||||
type Props = Omit<JSX.HTMLAttributes<HTMLDivElement>, "children" | "as"> & {
|
||||
error?: string;
|
||||
hover?: boolean;
|
||||
block?: boolean;
|
||||
spaced?: boolean;
|
||||
noMargin?: boolean;
|
||||
children?: Children;
|
||||
type?: "default" | "subtle" | "error" | "accent";
|
||||
};
|
||||
|
||||
const OverlineBase = styled.div<Omit<Props, "children" | "error">>`
|
||||
display: inline;
|
||||
transition: 0.2s ease filter;
|
||||
|
||||
${(props) =>
|
||||
props.hover &&
|
||||
css`
|
||||
cursor: pointer;
|
||||
transition: 0.2s ease filter;
|
||||
|
||||
&:hover {
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
!props.noMargin &&
|
||||
css`
|
||||
margin: 0.4em 0;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.spaced &&
|
||||
css`
|
||||
margin-top: 0.8em;
|
||||
`}
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--foreground);
|
||||
text-transform: uppercase;
|
||||
|
||||
${(props) =>
|
||||
props.type === "subtle" &&
|
||||
css`
|
||||
font-size: 12px;
|
||||
color: var(--secondary-foreground);
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.type === "error" &&
|
||||
css`
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--error);
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.type === "accent" &&
|
||||
css`
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--accent);
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.block &&
|
||||
css`
|
||||
display: block;
|
||||
`}
|
||||
`;
|
||||
|
||||
export default function Overline(props: Props) {
|
||||
return (
|
||||
<OverlineBase {...props}>
|
||||
{props.children}
|
||||
{props.children && props.error && <> · </>}
|
||||
{props.error && (
|
||||
<Overline type="error">
|
||||
<Text id={`error.${props.error}`}>{props.error}</Text>
|
||||
</Overline>
|
||||
)}
|
||||
</OverlineBase>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user