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")}
)}