From b0f3bec4d1cb23b410c415f81339caebeb740fea Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Tue, 20 Jan 2026 15:03:49 +0000 Subject: [PATCH] * add skeleton pulse animation * add translation strings * fix attachment view responsiveness --- .../public/locales/en-US/translation.json | 2 ++ .../components/attachment/attachment-view.tsx | 16 +++++++++++----- .../components/image/image-view.module.css | 18 ++++++++++++++++-- .../editor/components/image/image-view.tsx | 12 ++++++++---- .../components/video/video-view.module.css | 18 ++++++++++++++++-- .../editor/components/video/video-view.tsx | 12 ++++++++---- 6 files changed, 61 insertions(+), 17 deletions(-) diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index 8cb33378..0cdfbee0 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -328,6 +328,8 @@ "Upload any image from your device.": "Upload any image from your device.", "Upload any video from your device.": "Upload any video from your device.", "Upload any file from your device.": "Upload any file from your device.", + "Uploading {{name}}": "Uploading {{name}}", + "Uploading file": "Uploading file", "Table": "Table", "Insert a table.": "Insert a table.", "Insert collapsible block.": "Insert collapsible block.", diff --git a/apps/client/src/features/editor/components/attachment/attachment-view.tsx b/apps/client/src/features/editor/components/attachment/attachment-view.tsx index 48ab6cd6..e3281e64 100644 --- a/apps/client/src/features/editor/components/attachment/attachment-view.tsx +++ b/apps/client/src/features/editor/components/attachment/attachment-view.tsx @@ -4,8 +4,10 @@ import { getFileUrl } from "@/lib/config.ts"; import { IconDownload, IconPaperclip } from "@tabler/icons-react"; import { useHover } from "@mantine/hooks"; import { formatBytes } from "@/lib"; +import { useTranslation } from "react-i18next"; export default function AttachmentView(props: NodeViewProps) { + const { t } = useTranslation(); const { node, selected } = props; const { url, name, size } = node.attrs; const { hovered, ref } = useHover(); @@ -20,14 +22,18 @@ export default function AttachmentView(props: NodeViewProps) { wrap="nowrap" h={25} > - - {url ? : } + + {url ? ( + + ) : ( + + )} - - {url ? name : `Uploading ${name}...`} + + {url ? name : t("Uploading {{name}}", { name })} - + {formatBytes(size)} diff --git a/apps/client/src/features/editor/components/image/image-view.module.css b/apps/client/src/features/editor/components/image/image-view.module.css index 7d0dabf3..5d02184b 100644 --- a/apps/client/src/features/editor/components/image/image-view.module.css +++ b/apps/client/src/features/editor/components/image/image-view.module.css @@ -3,11 +3,25 @@ justify-content: center; align-items: center; border-radius: 8px; + overflow: hidden; + animation: pulse 1.2s ease-in-out infinite; + @mixin light { - background-color: var(--mantine-color-gray-0); + background: linear-gradient(-90deg, var(--mantine-color-gray-3) 0%, var(--mantine-color-gray-1) 50%, var(--mantine-color-gray-3) 100%); + background-size: 400% 400%; } @mixin dark { - background-color: var(--mantine-color-dark-7); + background: linear-gradient(-90deg, var(--mantine-color-dark-6) 0%, var(--mantine-color-dark-5) 50%, var(--mantine-color-dark-6) 100%); + background-size: 400% 400%; + } + + @keyframes pulse { + 0% { + background-position: 0% 0%; + } + 100% { + background-position: -135% 0%; + } } } diff --git a/apps/client/src/features/editor/components/image/image-view.tsx b/apps/client/src/features/editor/components/image/image-view.tsx index 6aa777f9..defb64c4 100644 --- a/apps/client/src/features/editor/components/image/image-view.tsx +++ b/apps/client/src/features/editor/components/image/image-view.tsx @@ -4,8 +4,10 @@ import { useMemo } from "react"; import { getFileUrl } from "@/lib/config.ts"; import clsx from "clsx"; import classes from "./image-view.module.css"; +import { useTranslation } from "react-i18next"; export default function ImageView(props: NodeViewProps) { + const { t } = useTranslation(); const { editor, node, selected } = props; const { src, width, align, title, aspectRatio, placeholder } = node.attrs; const alignClass = useMemo(() => { @@ -53,10 +55,12 @@ export default function ImageView(props: NodeViewProps) { )} {!src && !previewSrc && ( - - - - Uploading{placeholder?.name ? ` ${placeholder?.name}` : ""}... + + + + {placeholder?.name + ? t("Uploading {{name}}", { name: placeholder.name }) + : t("Uploading file")} )} diff --git a/apps/client/src/features/editor/components/video/video-view.module.css b/apps/client/src/features/editor/components/video/video-view.module.css index 95bce4ba..c0e7f99d 100644 --- a/apps/client/src/features/editor/components/video/video-view.module.css +++ b/apps/client/src/features/editor/components/video/video-view.module.css @@ -3,12 +3,26 @@ justify-content: center; align-items: center; border-radius: 8px; + overflow: hidden; + animation: pulse 1.2s ease-in-out infinite; + @mixin light { - background-color: var(--mantine-color-gray-0); + background: linear-gradient(-90deg, var(--mantine-color-gray-3) 0%, var(--mantine-color-gray-1) 50%, var(--mantine-color-gray-3) 100%); + background-size: 400% 400%; } @mixin dark { - background-color: var(--mantine-color-dark-7); + background: linear-gradient(-90deg, var(--mantine-color-dark-6) 0%, var(--mantine-color-dark-5) 50%, var(--mantine-color-dark-6) 100%); + background-size: 400% 400%; + } + + @keyframes pulse { + 0% { + background-position: 0% 0%; + } + 100% { + background-position: -135% 0%; + } } } .video { diff --git a/apps/client/src/features/editor/components/video/video-view.tsx b/apps/client/src/features/editor/components/video/video-view.tsx index c228265e..e2473afc 100644 --- a/apps/client/src/features/editor/components/video/video-view.tsx +++ b/apps/client/src/features/editor/components/video/video-view.tsx @@ -4,8 +4,10 @@ import { useMemo } from "react"; import { getFileUrl } from "@/lib/config.ts"; import clsx from "clsx"; import classes from "./video-view.module.css"; +import { useTranslation } from "react-i18next"; export default function VideoView(props: NodeViewProps) { + const { t } = useTranslation(); const { editor, node, selected } = props; const { src, width, align, aspectRatio, placeholder } = node.attrs; const alignClass = useMemo(() => { @@ -58,10 +60,12 @@ export default function VideoView(props: NodeViewProps) { )} {!src && !previewSrc && ( - - - - Uploading{placeholder?.name ? ` ${placeholder?.name}` : ""}... + + + + {placeholder?.name + ? t("Uploading {{name}}", { name: placeholder.name }) + : t("Uploading file")} )}