fix(mobile): fill the note column for images on narrow screens

A stored desktop width such as 35% stays in the note. Phone-width
layouts show the image at the text column width.
This commit is contained in:
tianma-if committed 2026-09-26 16:30:04 +08:00
1 parent 3725ab6f80
commit 0681e70c97
6 files changed
+61 -1

No files matched your search

+2 -1
View File
@@ -45,11 +45,12 @@ import {
import { createEdgeEverMathematics } from "@edgeever/shared/mathematics";
import { createIosImageGallery } from "./document-nodes";
import { createImageInsertTransaction, groupUploadedImages, NATIVE_IMAGE_GALLERY_CSS } from "@edgeever/shared/native-image-gallery";
import { NEW_IMAGE_WIDTH_PERCENT } from "@edgeever/shared/image-display";
import { installPhoneImageFillStyle, NEW_IMAGE_WIDTH_PERCENT } from "@edgeever/shared/image-display";
const galleryStyle = document.createElement("style");
galleryStyle.textContent = NATIVE_IMAGE_GALLERY_CSS;
document.head.append(galleryStyle);
installPhoneImageFillStyle();
const detailsStyle = document.createElement("style");
detailsStyle.textContent = DETAILS_EDITOR_CSS;
@@ -56,6 +56,7 @@ import {
DEFAULT_IMAGE_WIDTH_PERCENT,
NEW_IMAGE_WIDTH_PERCENT,
IMAGE_WIDTH_PRESETS,
PHONE_IMAGE_FILL_CSS,
clampImageWidth,
parseImageWidth,
} from "@edgeever/shared/image-display";
@@ -3358,5 +3359,6 @@ const getEditorStyles = (theme: "light" | "dark", options?: { viewer?: boolean }
.edgeever-image-upload-spinner { width: 18px; height: 18px; border: 2px solid ${theme === "dark" ? "#475569" : "#cbd5e1"}; border-top-color: #0f766e; border-radius: 999px; animation: edgeever-image-upload-spin 0.8s linear infinite; }
@keyframes edgeever-image-upload-spin { to { transform: rotate(360deg); } }
.edgeever-editor-content hr { margin: 24px 0; border: 0; border-top: 1px solid #cbd5e1; }
${PHONE_IMAGE_FILL_CSS}
`;
};
+3
View File
@@ -8,6 +8,7 @@ import { bootstrapI18n } from "./i18n";
import { emitPwaUpdateNotice } from "./lib/pwa-update-notice";
import { withEnvironmentTitlePrefix } from "./lib/environment-title";
import { initializeTheme, ThemeProvider } from "./components/ThemeProvider";
import { installPhoneImageFillStyle } from "@edgeever/shared/image-display";
import { applyEditorBodyFontPreference } from "./lib/editor-body-font";
import { installEditorBodyFontFaces } from "./lib/editor-body-font-faces";
import { applyUiFontPreference } from "./lib/ui-font";
@@ -16,6 +17,8 @@ import { reportDesktopRendererReadyAfterPaint } from "./lib/desktop-renderer-rea
import "./styles/globals.css";
import "./styles/editor-body-fonts.css";
installPhoneImageFillStyle();
const PWA_UPDATE_CHECK_INTERVAL_MS = 10 * 60 * 1_000;
const DEVELOPMENT_PWA_RELOAD_KEY = "edgeever.dev-pwa-reset";
const isDesktopRenderer = __EDGEEVER_DESKTOP_BUILD__ || window.edgeeverDesktop?.isAvailable === true;
+3
View File
@@ -6,11 +6,14 @@ import { initializeTheme } from "@/components/ThemeProvider";
import { applyEditorBodyFontPreference } from "@/lib/editor-body-font";
import { installEditorBodyFontFaces } from "@/lib/editor-body-font-faces";
import { applyUiFontPreference } from "@/lib/ui-font";
import { installPhoneImageFillStyle } from "@edgeever/shared/image-display";
import { bootstrapI18n } from "@/i18n";
import { defaultLocale, getBrowserLocale } from "@/i18n/locales";
import "./styles/mobile-markdown-editor.css";
import "./styles/editor-body-fonts.css";
installPhoneImageFillStyle();
declare global {
interface Window {
edgeeverMobileEditorBootstrap?: {
@@ -1,12 +1,17 @@
import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import {
DEFAULT_IMAGE_WIDTH_PERCENT,
NEW_IMAGE_WIDTH_PERCENT,
IMAGE_WIDTH_PRESETS,
PHONE_IMAGE_FILL_CSS,
PHONE_IMAGE_FILL_MAX_WIDTH_PX,
clampImageWidth,
parseImageWidth,
} from "./image-display.ts";
const readRepoFile = (relativePath) => readFileSync(new URL(relativePath, import.meta.url), "utf8");
describe("shared image display widths", () => {
test("keeps the four editor presets stable across clients", () => {
expect(DEFAULT_IMAGE_WIDTH_PERCENT).toBe(72);
@@ -26,4 +31,18 @@ describe("shared image display widths", () => {
expect(clampImageWidth(24.6)).toBe(25);
expect(clampImageWidth(71.6)).toBe(72);
});
test("fills the phone column without changing the stored desktop percent", () => {
expect(PHONE_IMAGE_FILL_MAX_WIDTH_PX).toBe(640);
expect(PHONE_IMAGE_FILL_CSS).toContain("@media screen and (max-width: 640px)");
expect(PHONE_IMAGE_FILL_CSS).toContain("width: 100% !important");
expect(PHONE_IMAGE_FILL_CSS).toContain("max-width: 100% !important");
expect(PHONE_IMAGE_FILL_CSS).toContain(".edgeever-image-node");
expect(PHONE_IMAGE_FILL_CSS).toContain(".ProseMirror img[data-width]");
expect(PHONE_IMAGE_FILL_CSS).toContain(":not(.edgeever-image-card *)");
expect(readRepoFile("../../../apps/mobile/src/components/LocalTiptapEditor.tsx")).toContain("${PHONE_IMAGE_FILL_CSS}");
expect(readRepoFile("../../../apps/ios/EditorSource/src/main.ts")).toContain("installPhoneImageFillStyle(");
expect(readRepoFile("../../../apps/web/src/main.tsx")).toContain("installPhoneImageFillStyle(");
expect(readRepoFile("../../../apps/web/src/mobile-edit.tsx")).toContain("installPhoneImageFillStyle(");
});
});
+32
View File
@@ -11,6 +11,38 @@ export const IMAGE_WIDTH_PRESETS = [
export const NEW_IMAGE_WIDTH_PERCENT = IMAGE_WIDTH_PRESETS[0].width;
/**
* Phone columns are already narrow. A desktop percent such as 35% ("较小")
* paints a stamp there, and the image action button covers most of it.
* At or below this viewport, images fill the column. The stored percent stays
* in the note for wide layouts.
*/
export const PHONE_IMAGE_FILL_MAX_WIDTH_PX = 640;
/**
* `!important` overrides the inline percent on the image figure.
* `screen` leaves print on the stored percent.
* Share-as-image cards (`.edgeever-image-card`) keep the stored percent:
* they are a fixed-width document, not the phone column.
*/
export const PHONE_IMAGE_FILL_CSS = `
@media screen and (max-width: ${PHONE_IMAGE_FILL_MAX_WIDTH_PX}px) {
:is(.edgeever-image-node, .edgeever-image-upload-result, .edgeever-image-upload-placeholder, .ProseMirror img[data-width]):not(.edgeever-image-card *) {
width: 100% !important;
max-width: 100% !important;
}
}
`;
export const installPhoneImageFillStyle = () => {
if (typeof document === "undefined") return;
if (document.head.querySelector("style[data-edgeever-phone-image-fill]")) return;
const style = document.createElement("style");
style.dataset.edgeeverPhoneImageFill = "true";
style.textContent = PHONE_IMAGE_FILL_CSS;
document.head.append(style);
};
export type ImageWidthPresetId = (typeof IMAGE_WIDTH_PRESETS)[number]["id"];
export const clampImageWidth = (width: number): number =>