diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 68ea04de..00000000 --- a/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -tabWidth: 4 \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000..ae7b27fb --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,9 @@ +module.exports = { + "tabWidth": 4, + "useTabs": true, + "trailingComma": "all", + "jsxBracketSameLine": true, + "importOrder": ["/(lib)", "/(redux)", "/(context)", "/(ui|common)|.svg$", "^[./]"], + "importOrderSeparation": true, +} + \ No newline at end of file diff --git a/package.json b/package.json index ec6f6d2d..2e298ff3 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@tippyjs/react": "^4.2.5", "@traptitech/markdown-it-katex": "^3.4.3", "@traptitech/markdown-it-spoiler": "^1.1.6", + "@trivago/prettier-plugin-sort-imports": "^2.0.2", "@types/lodash.defaultsdeep": "^4.6.6", "@types/lodash.isequal": "^4.5.5", "@types/markdown-it": "^12.0.2", diff --git a/src/components/common/LocaleSelector.tsx b/src/components/common/LocaleSelector.tsx index 225e2c38..7f91b1c7 100644 --- a/src/components/common/LocaleSelector.tsx +++ b/src/components/common/LocaleSelector.tsx @@ -1,9 +1,9 @@ import ComboBox from "../ui/ComboBox"; +import { dispatch } from "../../redux"; import { connectState } from "../../redux/connector"; -import { WithDispatcher } from "../../redux/reducers"; import { Language, LanguageEntry, Languages } from "../../context/Locale"; -type Props = WithDispatcher & { +type Props = { locale: string; }; @@ -12,8 +12,7 @@ export function LocaleSelector(props: Props) { - props.dispatcher && - props.dispatcher({ + dispatch({ type: "SET_LOCALE", locale: e.currentTarget.value as Language }) @@ -37,6 +36,5 @@ export default connectState( return { locale: state.locale }; - }, - true + } ); diff --git a/src/components/common/messaging/MessageBox.tsx b/src/components/common/messaging/MessageBox.tsx index b035bfa6..486f6f28 100644 --- a/src/components/common/messaging/MessageBox.tsx +++ b/src/components/common/messaging/MessageBox.tsx @@ -1,11 +1,11 @@ import { ulid } from "ulid"; import { Text } from "preact-i18n"; -import Tooltip, { PermissionTooltip } from "../Tooltip"; import { Channel } from "revolt.js"; import styled from "styled-components"; +import { dispatch } from "../../../redux"; import { defer } from "../../../lib/defer"; import IconButton from "../../ui/IconButton"; -import { X } from '@styled-icons/boxicons-regular'; +import { PermissionTooltip } from "../Tooltip"; import { Send } from '@styled-icons/boxicons-solid'; import { debounce } from "../../../lib/debounce"; import Axios, { CancelTokenSource } from "axios"; @@ -13,7 +13,6 @@ import { useTranslation } from "../../../lib/i18n"; import { Reply } from "../../../redux/reducers/queue"; import { connectState } from "../../../redux/connector"; import { SoundContext } from "../../../context/Settings"; -import { WithDispatcher } from "../../../redux/reducers"; import { takeError } from "../../../context/revoltjs/util"; import TextAreaAutoSize from "../../../lib/TextAreaAutoSize"; import AutoComplete, { useAutoComplete } from "../AutoComplete"; @@ -30,9 +29,8 @@ import { ShieldX } from "@styled-icons/boxicons-regular"; import ReplyBar from "./bars/ReplyBar"; import FilePreview from './bars/FilePreview'; -import { Styleshare } from "@styled-icons/simple-icons"; -type Props = WithDispatcher & { +type Props = { channel: Channel; draft?: string; }; @@ -77,7 +75,7 @@ const Action = styled.div` // ! FIXME: add to app config and load from app config export const CAN_UPLOAD_AT_ONCE = 5; -function MessageBox({ channel, draft, dispatcher }: Props) { +function MessageBox({ channel, draft }: Props) { const [ uploadState, setUploadState ] = useState({ type: 'none' }); const [ typing, setTyping ] = useState(false); const [ replies, setReplies ] = useState([]); @@ -102,13 +100,13 @@ function MessageBox({ channel, draft, dispatcher }: Props) { function setMessage(content?: string) { if (content) { - dispatcher({ + dispatch({ type: "SET_DRAFT", channel: channel._id, content }); } else { - dispatcher({ + dispatch({ type: "CLEAR_DRAFT", channel: channel._id }); @@ -148,7 +146,7 @@ function MessageBox({ channel, draft, dispatcher }: Props) { playSound('outbound'); const nonce = ulid(); - dispatcher({ + dispatch({ type: "QUEUE_ADD", nonce, channel: channel._id, @@ -171,7 +169,7 @@ function MessageBox({ channel, draft, dispatcher }: Props) { replies }); } catch (error) { - dispatcher({ + dispatch({ type: "QUEUE_FAIL", error: takeError(error), nonce @@ -383,7 +381,7 @@ function MessageBox({ channel, draft, dispatcher }: Props) { ) } -export default connectState>(MessageBox, (state, { channel }) => { +export default connectState>(MessageBox, (state, { channel }) => { return { draft: state.drafts[channel._id] } diff --git a/src/components/common/messaging/attachments/Attachment.module.scss b/src/components/common/messaging/attachments/Attachment.module.scss index 5aa89744..8b5529d4 100644 --- a/src/components/common/messaging/attachments/Attachment.module.scss +++ b/src/components/common/messaging/attachments/Attachment.module.scss @@ -1,14 +1,13 @@ .attachment { + display: grid; + grid-auto-columns: min(100%, 480px); + grid-auto-flow: row dense; + + width: max-content; + border-radius: 6px; margin: .125rem 0 .125rem; - height: auto; - - max-height: 640px; - max-width: min(480px, 100%); - - object-fit: contain; - &[data-spoiler="true"] { filter: blur(30px); pointer-events: none; @@ -20,6 +19,16 @@ &.image { cursor: pointer; + + max-height: 640px; + max-width: min(480px, 100%); + + object-fit: contain; + + &.loaded { + width: auto; + height: auto; + } } &.video { @@ -29,8 +38,15 @@ } video { - width: 100%; border-radius: 0 0 6px 6px; + + max-height: 640px; + max-width: min(480px, 100%); + } + + video.loaded { + width: auto; + height: auto; } } @@ -59,11 +75,12 @@ } &.text { - display: flex; - overflow: hidden; + width: 100%; max-width: 800px; + overflow: hidden; + grid-auto-columns: unset; + border-radius: 6px; - flex-direction: column; .textContent { height: 140px; @@ -92,35 +109,48 @@ } } +.actions.imageAction { + grid-template: + "name icon download" auto + "size icon download" auto + / minmax(20px, 1fr) min-content min-content; +} + .actions { - gap: 8px; - padding: 8px; - display: flex; - overflow: none; - max-width: 100%; + display: grid; + grid-template: + "icon name download" auto + "icon size download" auto + / min-content minmax(20px, 1fr) min-content; + align-items: center; - flex-direction: row; + column-gap: 8px; + + width: 100%; + padding: 8px; + overflow: none; + color: var(--foreground); background: var(--secondary-background); - > svg { - flex-shrink: 0; + span { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } - .info { - display: flex; - flex-direction: column; - flex-grow: 1; + .filesize { + grid-area: size; - > span { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } + font-size: 10px; + color: var(--secondary-foreground); + } - .filesize { - font-size: 10px; - color: var(--secondary-foreground); - } + .downloadIcon { + grid-area: download; + } + + .iconType { + grid-area: icon; } } diff --git a/src/components/common/messaging/attachments/Attachment.tsx b/src/components/common/messaging/attachments/Attachment.tsx index 15c42536..2ef979a2 100644 --- a/src/components/common/messaging/attachments/Attachment.tsx +++ b/src/components/common/messaging/attachments/Attachment.tsx @@ -21,6 +21,7 @@ export default function Attachment({ attachment, hasContent }: Props) { const { openScreen } = useIntermediate(); const { filename, metadata } = attachment; const [ spoiler, setSpoiler ] = useState(filename.startsWith("SPOILER_")); + const [ loaded, setLoaded ] = useState(false) const url = client.generateFileURL(attachment, { width: MAX_ATTACHMENT_WIDTH * 1.5 }, true); @@ -44,7 +45,7 @@ export default function Attachment({ attachment, hasContent }: Props) { height={metadata.height} data-spoiler={spoiler} data-has-content={hasContent} - className={classNames(styles.attachment, styles.image)} + className={classNames(styles.attachment, styles.image, loaded && styles.loaded)} onClick={() => openScreen({ id: "image_viewer", attachment }) } @@ -52,6 +53,7 @@ export default function Attachment({ attachment, hasContent }: Props) { ev.button === 1 && window.open(url, "_blank") } + onLoad={() => setLoaded(true)} /> ); @@ -85,11 +87,15 @@ export default function Attachment({ attachment, hasContent }: Props) {