Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ All notable changes to SourceDraft are documented here. The project uses [Semant
and Settings, a consistent button system, and the Publish action as a large,
anchored, high-contrast primary button. Reduced visual noise via tokens.
- Added `.claude/rules/ui-standards.md` as the authoritative Studio UI bar.
- **Editor link/image/file insertion (Phase 4b)** — replaced the blocking
`window.prompt` link, image, and file-link flows (toolbar and slash commands)
with an accessible in-Studio dialog (labelled fields, Enter to submit, Escape
to cancel, bare-domain URLs gain `https://`). Removed the unused legacy
`MarkdownToolbar`.

## v0.1.0

Expand Down
56 changes: 56 additions & 0 deletions apps/studio/e2e/smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,62 @@ test.describe("Studio smoke", () => {
await expect(page.getByRole("button", { name: "Insert file link" })).toBeVisible();
});

test("link toolbar button opens an inline dialog and inserts a link", async ({
page,
}) => {
await enterDemoMode(page);
await page.getByRole("button", { name: "New article" }).click();
await fillPostBody(page, "Intro paragraph.");

await page.getByRole("button", { name: "Insert or edit link" }).click();
const dialog = page.getByRole("dialog", { name: "Insert link" });
await expect(dialog).toBeVisible();

await dialog.getByLabel("Link URL").fill("example.com");
await dialog.getByLabel("Link text").fill("Example site");
await dialog.getByRole("button", { name: "Insert link" }).click();

await expect(dialog).toBeHidden();
const link = postBodyEditor(page).getByRole("link", { name: "Example site" });
await expect(link).toBeVisible();
await expect(link).toHaveAttribute("href", "https://example.com");
});

test("image toolbar button opens an inline dialog and inserts an image", async ({
page,
}) => {
await enterDemoMode(page);
await page.getByRole("button", { name: "New article" }).click();
await fillPostBody(page, "Before image.");

await page.getByRole("button", { name: "Insert image", exact: true }).click();
const dialog = page.getByRole("dialog", { name: "Insert image" });
await expect(dialog).toBeVisible();

await dialog.getByLabel("Image path or URL").fill("/images/example.jpg");
await dialog.getByLabel("Alt text (for accessibility)").fill("Example");
await dialog.getByRole("button", { name: "Insert image" }).click();

await expect(dialog).toBeHidden();
await expect(postBodyEditor(page).locator("img")).toHaveAttribute(
"src",
"/images/example.jpg",
);
});

test("insert dialog closes on Escape without inserting", async ({ page }) => {
await enterDemoMode(page);
await page.getByRole("button", { name: "New article" }).click();
await fillPostBody(page, "Body text.");

await page.getByRole("button", { name: "Insert or edit link" }).click();
const dialog = page.getByRole("dialog", { name: "Insert link" });
await expect(dialog).toBeVisible();
await dialog.getByLabel("Link URL").press("Escape");
await expect(dialog).toBeHidden();
await expect(postBodyEditor(page).getByRole("link")).toHaveCount(0);
});

test("autosave status appears after edits", async ({ page }) => {
await enterDemoMode(page);
await page.getByRole("button", { name: "New article" }).click();
Expand Down
186 changes: 0 additions & 186 deletions apps/studio/src/components/MarkdownToolbar.tsx

This file was deleted.

Loading
Loading