Release v0.4.0: dev -> main #251

Merged
fen merged 138 commits from dev into main 2026-09-17 15:35:21 +00:00
Collaborator

Ref #160

Release PR for v0.4.0. Brings dev (cf6e52b) to main:

  • #243/#244/#245: copy/link buttons (copy = content, new link button copies the paste URL), capitalized action buttons, label persistence
  • #247: reserve mine/unlock/guess/f custom slugs
  • #246: README refresh for v0.4.0 with fresh screenshots (issue #160)
  • prior dev accumulation since v0.3.0: attachment fixes, pagination, burn-after-read UI, theme/settings work

Merging this creates the v0.4.0 tag build.

Ref #160 Release PR for v0.4.0. Brings dev (cf6e52b) to main: - #243/#244/#245: copy/link buttons (copy = content, new link button copies the paste URL), capitalized action buttons, label persistence - #247: reserve mine/unlock/guess/f custom slugs - #246: README refresh for v0.4.0 with fresh screenshots (issue #160) - prior dev accumulation since v0.3.0: attachment fixes, pagination, burn-after-read UI, theme/settings work Merging this creates the v0.4.0 tag build.
fen added 138 commits 2026-09-17 15:34:49 +00:00
Admin lock: replace explanation paragraph with centered key input
CI / test (pull_request) Successful in 28s
CI / docker (pull_request) Skipped
8dde83ff68
Fix #120: add matching light/dark variant for every theme
CI / test (pull_request) Successful in 31s
CI / docker (pull_request) Skipped
70c284b15d
UI polish: placeholder slash, styled controls, admin link spacing (#123)
CI / test (pull_request) Successful in 24s
CI / docker (pull_request) Skipped
1e317d11da
Remove custom URL reservation note and Can contents menu from new paste page
CI / test (pull_request) Successful in 25s
CI / docker (pull_request) Skipped
8104cdba4c
Fixes #124
Merge dev into fix-124: resolve new.html conflict, keep #124 removals and #125 placeholder
CI / test (pull_request) Successful in 25s
CI / docker (pull_request) Skipped
8eabeb4839
- Collapse the 10 theme cards into 5 pairs: light swatches top row, dark bottom row
- Dark mode toggle in settings and topbar (sun/moon inline SVG)
- Toggling dark mode switches to the other variant of the selected pair
- Persist pair id in localStorage palette-theme, dark flag in palette-dark
- Head script resolves base+dark to variant; URL ?theme= accepts both ids and wins
- Settings gear highlights like nav tabs on /settings
- PALETTE_DEFAULT_DARK env var sets server default dark state (default on)
- Server-side resolution helpers + tests
Theme pairs with dark mode toggle, gear active state, PALETTE_DEFAULT_DARK (#127)
CI / test (pull_request) Successful in 25s
CI / docker (pull_request) Skipped
dcf2d66a82
- Collapse the 10 theme cards into 5 pairs: light swatches top row, dark bottom row
- Dark mode toggle in settings and topbar (sun/moon inline SVG)
- Toggling dark mode switches to the other variant of the selected pair
- Persist pair id in localStorage palette-theme, dark flag in palette-dark
- Head script resolves base+dark to variant; URL ?theme= accepts both ids and wins
- Settings gear highlights like nav tabs on /settings
- PALETTE_DEFAULT_DARK env var sets server default dark state (default on)
- Server-side resolution helpers + tests
#38 iteration 1: file attachments, 1 file per paste
CI / test (pull_request) Successful in 26s
CI / docker (pull_request) Skipped
4948ef9f1c
- internal/store/blob.go: BlobStore interface + fs implementation with
  traversal-safe keys (<paste-id>/<sha256>), put/get/stat/delete
- attachments table migration (id, paste_id, filename sanitized to 255,
  mime sniffed server-side, size, sha256, created_at)
- POST /api/pastes now accepts multipart/form-data with a 'file' part;
  1 file = 1 paste: file replaces text content when both are sent
- 25 MB per-file limit enforced server-side (413 file_too_large)
- GET /f/{attachment-id}/{filename}: stored sniffed mime, nosniff,
  inline only for images/pdf, html/svg/xml forced to text/plain (#34 rule)
- paste view renders attachment chip + inline image preview
- /new: dropzone with file picker, drag-and-drop, Ctrl+V file paste,
  file chip with name/size/remove, matches pill/radius design
- tests: blob roundtrip/traversal/sanitize; multipart create (mime
  sniffing, client mime ignored, size limit, two-file reject, html/svg
  forcing, 404s, password/expiry fields)
Add line wrap toggle for editor and paste viewer (#130)
CI / test (pull_request) Successful in 27s
CI / docker (pull_request) Skipped
7cc6a9c706
Shared client-side preference in localStorage 'palette-wrap', default
off. Toggle button on /new editor head and paste title bar, plus a Line
wrap checkbox in the settings menu; all read/write the same preference.
Active state uses the accent treatment like other toggles. No em dashes
in UI text.
Fix result box wrap: word boundaries instead of break-all (#135)
CI / test (pull_request) Successful in 26s
CI / docker (pull_request) Skipped
9f4ed91b8f
History: keep pagination over filtered/sorted set, pin pager to page bottom (#133)
CI / test (pull_request) Successful in 26s
CI / docker (pull_request) Skipped
fa2e9b1bb5
#38 QA fix: render GetAttachmentForPaste in paste view; dedupe dark-toggle CSS
CI / test (pull_request) Successful in 27s
CI / docker (pull_request) Skipped
0073335875
- renderPaste now looks up the paste's attachment and passes it as
  'Attachment' so the paste.html attachment chip/image preview renders
- remove duplicated .iconbtn.dark-toggle blocks (3x from stacked
  branches #127/#128) and duplicate mobile-media variants

Verified: go vet + go test pass; live render on :18098 shows
attachment-chip + img src=/f/id/name for a png upload (served 200
image/png) and chip-with-filename, no preview, for an html upload.
Fix #146: render untitled paste ID fallback as plain text like titled pastes
CI / test (pull_request) Successful in 26s
CI / docker (pull_request) Skipped
7dc70d62f6
The PASTE column fallback for untitled pastes used the .slug class, which
renders as a monospace chip with a background pill. Give it a dedicated
paste-name modifier that strips the chip styling (background, padding,
radius, mono font) so the fallback looks identical to a titled paste
(var(--fg) plain text). The dedicated ID column and URL column chips keep
their existing styling. Applied to both /history and /mine tables.
Split new-paste editor header into title pill and settings pill (#147)
CI / test (pull_request) Successful in 30s
CI / docker (pull_request) Skipped
da9039b606
Merge fix-38-file-attachments into dev (PR #129)
CI / test (push) Successful in 28s
CI / docker (push) Successful in 36s
22c66243d5
Require secrets via headers only: drop ?key= and ?password= query fallbacks (#137, #141)
CI / test (pull_request) Successful in 28s
CI / docker (pull_request) Skipped
d013f3965f
Query strings leak into Traefik access logs, browser history, and Referer
headers. Admin key is now accepted only via X-Admin-Key; paste and can
passwords only via X-Paste-Password (or the POST unlock form). Tests
updated; new negative cases assert 401 for the query paths.
Fix invisible select chevron in all presets (#136)
CI / test (pull_request) Successful in 28s
CI / docker (pull_request) Skipped
72dbfb1b3c
Two compounding causes:
- CSP img-src fell back to default-src (self), blocking the data: URI
  chevron image on all served pages, so no select ever painted it.
- .editor-head select used the background shorthand, wiping the
  background-image set by the later select rule.

Chevron stroke is now a per-preset --chevron token (light stroke for
dark presets, dark for light presets) instead of hardcoded #888.
CSP gains img-src 'self' data: so the data-URI icons can load.
Settings: dark toggle above theme list; midnight card light row on top (#132)
CI / test (pull_request) Successful in 29s
CI / docker (pull_request) Skipped
747eba7064
The deletion token was accepted via the ?token= query parameter on both
DELETE /api/pastes/{id} and /redeem, and round-tripped through the paste
URL after creation. URL-carried bearer secrets leak into reverse-proxy
access logs and browser history.

- API: deletion tokens are now accepted only via the Authorization header
  (Bearer/Token/bare); query params are ignored on both endpoints
- Web create flow: token moves to the browser via a short-lived tok_<id>
  HttpOnly cookie instead of the redirect URL; the paste view reads it
  from the cookie, never from ?token=
- Web view: the delete button calls redeem() which takes the token from
  sessionStorage and sends it as an Authorization header
- Tests: correct token in query must be rejected (403/400); header path
  still deletes/redeems; extraction unit cases updated

Fixes #143
#143: set tok_<id> cookie in create handlers so the created banner can show the token (QA)
CI / test (pull_request) Successful in 29s
CI / docker (pull_request) Skipped
00aaafeb3c
Merge pull request 'Remove ?token= deletion-token path (#143)' (#153) from fix-143 into dev
CI / test (push) Successful in 29s
CI / docker (push) Successful in 36s
fe75dfc746
#138: add Secure attribute to viewer cookie (vwr)
CI / test (pull_request) Successful in 29s
CI / docker (pull_request) Skipped
521b6f8011
Wrap ON breaks long tokens mid-word; no horizontal scroll while wrap enabled (#152)
CI / test (pull_request) Successful in 30s
CI / docker (pull_request) Skipped
b30d41b87d
- codebody/editor: overflow-wrap anywhere + word-break break-all + overflow-x hidden under html[data-wrap]
- code container and mobile .float also hidden overflow with wrap on
- topbar mobile: tighten gap/padding/nav link padding so nothing overflows at 375px

Fixes #152
Fix #139: drop unsafe-inline from script-src and style-src (#139)
CI / test (pull_request) Successful in 30s
CI / docker (pull_request) Skipped
7a74ff3e74
- Move all inline <script> blocks (layout head/theme, topbar dark toggle,
  foot, paste, new, history, mine, settings, admin, unlock) to external
  files under internal/web/static/. Page data reaches scripts via data-*
  attributes (data-paste-id, data-default-dark) instead of template vars.
- Replace inline onclick handlers (copy, delete, stats toggle) with
  addEventListener wiring.
- Convert inline style="" attributes to CSS utility classes; swatch
  colors are now set via CSSOM/DOM APIs instead of innerHTML strings.
- script-src/style-src are now plain 'self'; img-src data: stays for the
  SVG data-URI backgrounds. Verified with headless chromium: zero CSP
  violations on all pages in dark and light presets, theme swatches,
  admin lock, tables and paste view render correctly.
Fix #142: break long unbroken paste titles instead of forcing horizontal scroll
CI / test (pull_request) Successful in 34s
CI / docker (pull_request) Skipped
c4d55cb196
Add word-break: normal; overflow-wrap: anywhere to .paste-title-bar h1 so
a >120-char unbroken title wraps inside the title card at mobile width
instead of producing an internal + page-level horizontal scrollbar.
Fix #163: remove dead iscan/createCan path breaking /new Create
CI / test (pull_request) Successful in 31s
CI / docker (pull_request) Skipped
0787871f2b
Settings: more padding between sections (#161)
CI / test (pull_request) Successful in 37s
CI / docker (pull_request) Skipped
317ed2137a
Add margin under the dark mode toggle and between section headings
(theme/editor) on /settings via CSS classes, no inline styles (CSP).
new paste tab: rework number box submenus (#157)
CI / test (pull_request) Successful in 32s
CI / docker (pull_request) Skipped
16cad8796f
Give the custom expiry and readable N times submenus a shared boxed
container with proper padding, indent them under their parent option,
and style the number inputs and unit select with palette vars, the
existing radius scale, and the select chevron. No em dashes, no hard
coded colors in new rules.
new paste tab: rework number box submenus (#157)
CI / test (push) Successful in 31s
CI / docker (push) Successful in 37s
4683b8b542
Fixes #157
Merge pull request 'Settings spacing between sections (#161)' (#165) from fix-161 into dev
CI / test (push) Successful in 31s
CI / docker (push) Successful in 39s
5dba356264
editor head: wrap toggle state and pill highlight (#166)
CI / test (pull_request) Successful in 32s
CI / docker (pull_request) Skipped
5fc5ae8aad
wrap button on the new paste page looked identical whether wrap was on
or off because the btn base is already accent filled. give the toggle a
neutral off state so the accent on state is visible, matching the icon
button toggles on the paste view.

also remove the accent border on the whole language settings pill when
any child has focus. individual controls already show their own focus
rings, so the pill highlight made no sense.
Missing/expired/burned paste IDs and unknown routes now render the main
UI (topbar + centered result card) with a 'Paste ID not found' message,
returning HTTP 404 status for correctness.
web: friendly Paste ID not found page for missing pastes (#173)
CI / test (pull_request) Successful in 32s
CI / docker (pull_request) Skipped
122c1e14f4
Missing or expired paste IDs (and unknown routes) now render the main
UI chrome with a 'Paste ID not found' message in a color-coded result
card instead of a bare text/JSON 404. HTTP status stays 404. No inline
scripts or styles; new CSS uses existing --err token and pill radii.
- images render fitted into the editor area (object-fit contain), editor hidden
- text files load content into the editor; title placeholder convention (Python.py, Text.txt fallback)
- title auto-fills only when blank; never overwrites a typed title
- external JS + CSS classes only, CSP-safe (no inline styles/scripts)
Merge pull request 'File upload preview in editor (#171)' (#175) from fix-171 into dev
CI / test (push) Successful in 32s
CI / docker (push) Successful in 40s
b9153c1d95
Fix #170: stray bar at bottom of /new page
CI / test (pull_request) Successful in 36s
CI / docker (pull_request) Skipped
d7fb87f19b
#139 removed inline display:block from paste.html's created banner and
compensated with a global .created-banner { display:block } override.
That override also hit the hidden placeholder banner on /new, whose
base rule is display:none, making an empty padded bar render above the
action bar. Scope the override to .created-banner.show and mark only
the paste-view banner with the show class.
clean up notification pill wording, size, and placement (#168)
CI / test (pull_request) Successful in 39s
CI / docker (pull_request) Skipped
3fa2c93e22
# Conflicts:
#	internal/web/templates/paste.html
Fix #167: gutter numbers track wrapped visual rows when line wrap enabled
CI / test (pull_request) Successful in 38s
CI / docker (pull_request) Skipped
dee062dfa5
Merge remote fix-168: keep corner pill, cookie-based token flow
CI / test (pull_request) Successful in 40s
CI / docker (pull_request) Skipped
6064404723
Merge pull request 'Clean up notification pill (#168)' (#178) from fix-168 into dev
CI / test (push) Successful in 40s
CI / docker (push) Successful in 50s
362a59690f
Revise notification pill per reopened #168: short text, smaller, side placement
CI / test (pull_request) Successful in 40s
CI / docker (pull_request) Skipped
b801d7fb56
- Pill now reads only 'Paste Created' (no combined 'Paste Created - Link Copied')
- Copy fallback toast now says 'Link Copied'
- Pill shrunk (smaller padding/font) and anchored tighter to the right side

Fixes #168
Fix #167 rev: add missing .gutline CSS so gutter numbers align with wrapped lines
CI / test (pull_request) Successful in 41s
CI / docker (pull_request) Skipped
9692531a40
QA of PR #179 found paste-lines.js creates .gutline spans but no CSS rule
existed, so all gutter numbers rendered inline on one visual row. Stack
them one per row under .code .gutter; blank fill spans inherit it.
Fix #171 (r2): file image preview uses data: URL (FileReader) instead of blob: for CSP compliance
CI / test (pull_request) Successful in 41s
CI / docker (pull_request) Skipped
bb7251bd25
Merge pull request 'Revise notification pill (#168)' (#181) from fix-168 into dev
CI / test (push) Successful in 42s
CI / docker (push) Successful in 50s
0e5cfcd403
Revise notification pill per reopened #168: short text, smaller, side placement
CI / test (pull_request) Successful in 39s
CI / docker (pull_request) Skipped
f6c7bfa66b
- Pill now reads only 'Paste Created' (no combined 'Paste Created - Link Copied')
- Copy fallback toast now says 'Link Copied'
- Pill shrunk (smaller padding/font) and anchored tighter to the right side

Fixes #168
fix #171: use FileReader data: URL for image preview (CSP blocks blob:)
CI / test (pull_request) Successful in 39s
CI / docker (pull_request) Skipped
f947415b23
Merge pull request 'Revise notification pill (#168)' (#180) from fix-168 into dev
CI / test (push) Successful in 39s
CI / docker (push) Successful in 56s
02fcb80b6d
Fix #167: block-level gutline spans so gutter numbers align with wrapped lines
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
158c0fe4b6
QA on dev showed .codeline spans wrap correctly but gutter .gutline spans
rendered inline (all at the same top), so numbers 6+ fell off with wrap on.
Add .gutter .gutline { display: block; } so each gutter number occupies its
own visual row, matching the one-number-per-visual-row contract of
paste-lines.js. Verified rendered output in a local build at 1400x900 and
375x812 with a long unbroken token on line 5 and wrap ON.
Fix #169: persistent full-width divider under stats dropdown title
CI / test (pull_request) Successful in 40s
CI / docker (pull_request) Skipped
80e761f53d
The divider between the stats dropdown head and body lived on
.stats-body's border-top, so it vanished when collapsed and only the
hover background hinted at the boundary (flicker). Move it to
.stats-head border-bottom so it is always present and spans the full
pill width.
Merge pull request 'Fix #167: gutter realignment with wrapped lines' (#188) from fix-167 into dev
CI / test (push) Successful in 40s
CI / docker (push) Successful in 45s
CI / test (pull_request) Successful in 47s
CI / docker (pull_request) Skipped
1a8da8cd7a
# Conflicts:
#	internal/web/static/app.css
Merge fix-171-r2 into dev (QA for #185): take dev's new.js (already data:-URL) for conflict
CI / test (push) Successful in 45s
CI / docker (push) Successful in 51s
9621faa052
Fix #184: file upload replaces the main editing area on /new
CI / test (pull_request) Successful in 48s
CI / docker (pull_request) Skipped
6c1bfaf15e
Image files render fitted into the editor area (editor and gutter
hidden); the title auto-fills with the file name. Text files always
load their content into the editor, replacing any text already there,
instead of only filling an empty editor. Title auto-fill still only
applies when the title is blank; a typed title is never overwritten.
Drawing and cropping tools are noted in the issue as possible future
work and are intentionally not implemented here.
Fix #169: persistent full-width divider between dropdown title and body
CI / test (pull_request) Successful in 46s
CI / docker (pull_request) Skipped
179eb17da9
The can page 'Show content' dropdown had no divider between the summary
title and the body; the only line-like artifact appeared hover-dependent
(the stats header hover background edge). Per the owner follow-up, the
divider between a dropdown title and its body must be persistent (not
hover dependent) and extend the full width of the card left and right.

can page: .can-item-body[open] summary now carries a permanent 1px
var(--border) bottom rule spanning the full card width via negative
margins matching the card padding, plus matching bottom padding.
Fix #187: add favicon (paint palette)
CI / test (pull_request) Successful in 39s
CI / docker (pull_request) Skipped
2a21251c47
Fix #194 r2: align line-number gutter in both wrap modes
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
1f5e671a43
QA FAIL of PR #179 (verified on palette-dev 2026-09-10) found two defects:

1) Row accounting: splitLines() joined .codeline blocks with '\n' text
   nodes. Since dee062d made .codeline display:block, each interleaved
   newline text node rendered as its own extra visual row in the code
   column under pre-wrap, but renumber() counted only .codeline span
   heights, so the gutter had one fewer row per line break and numbers
   drifted off alignment on wrapped lines. Fix: join('') so blocks are
   adjacent with no phantom newline rows; blank source lines become
   empty blocks given a line box via .codeline:empty::before (ZWJ) in
   app.css so they still count as one row.

2) Inline gutter spans: .gutline spans were appended with no separators
   and .code .gutter .gutline { display: block } did not exist on the
   deployed build, so all numbers landed on one row. That rule is
   present in origin/dev (merged via #183); kept unchanged and verified
   by rendering in a local build.

Wrap OFF path unchanged: gutter still gets '1\n2\n3\n4' text and the
horizontal-scroll gutter behavior is untouched (no CSS changes to
scrolling; only a :empty line-box rule). CSP unchanged: no inline
styles/handlers, static JS only.
Fix #167: renumber gutter to visual rows when line wrap is on
CI / test (pull_request) Successful in 39s
CI / docker (pull_request) Skipped
e430eb57b7
Split the paste codebody into per-line block spans (paste-lines.js) and
rebuild the gutter from each line's wrapped height so numbers count
visual rows, not logical lines. Pinned the gutter width (flex 0 0 auto,
3ch) so its row count no longer feeds back into the code column width.
ResizeObserver renumbers on wrap toggle / resize; wrap-off behavior is
unchanged (one number per newline).
Fix #167: gutter numbers align with wrapped-line starts
CI / test (pull_request) Successful in 49s
CI / docker (pull_request) Skipped
2149fcc2e1
- splitLines(): join .codeline blocks with "" not "\n" — newline text
  nodes under pre-wrap rendered an extra line box per logical line, so
  every gutter number drifted one row per line
- renumber(): geometry-driven placement — one gutline per visual row of
  the code body, each number assigned to the row matching its line's
  measured offsetTop; verified second pass re-runs if a partially-filled
  last wrapped row reflows after the gutter rebuild
- app.css: mobile media query gives .code .gutter the same 13px font as
  .code so gutter rows and code rows share one line box at 375px

Verified in local build with headless chromium (long unbroken token on
line 5, wrap ON): all numbers align with line starts, no misalignment,
no horizontal scroll at 1400x900 and 375x812.
Fix settings dark mode toggle double-binding and center it (#197)
CI / test (pull_request) Successful in 50s
CI / docker (pull_request) Skipped
8042116a69
topbar.js binds click handlers to every .dark-toggle, including the
settings one; settings.js then also wired a delegation that re-clicked
the topbar button, so each click flipped dark mode twice (net no-op).
Mark buttons as wired in topbar.js and only add a fallback handler in
settings.js when topbar.js did not run.

CSS: center the toggle horizontally under the Settings title with auto
margins, matching .settings-body padding.

Closes #197
Fix #167: align gutter numbers with actual rendered line rows (wrap ON)
CI / test (pull_request) Successful in 44s
CI / docker (pull_request) Skipped
5fdb34a059
paste-lines.js joined .codeline spans with '\n' text nodes that pre-wrap
renders as extra line boxes, and renumber() counted per-line span heights
(rounding) instead of real geometry, so gutter numbers drifted off their
line starts on wrapped lines. Fix: join spans with '' (blocks need no
newline text), and build one .gutline per visual row measured from the
code body's real height, placing each number at the visual row whose top
matches its .codeline's measured top. Wrap OFF path unchanged. Mobile
font-size rule added so gutter row pitch matches code rows at 375x812.
Fix #167: gutter alignment with wrap on
CI / test (pull_request) Successful in 46s
CI / docker (pull_request) Skipped
e1056df747
Rebuild renumber() so gutter numbers are placed by measured geometry:
each .gutline block is one visual row and each number is assigned to the
row whose top matches its .codeline's top, instead of counting rows per
line. This keeps numbers aligned with wrapped line starts regardless of
how many visual rows a line occupies. Wrap OFF path unchanged.
Merge fix-167 (PR #200) into dev
CI / test (push) Successful in 38s
CI / docker (push) Successful in 43s
f1665f1b31
Resolves #167

QA: fen
Fix #167 r2: measure-based gutter rows + fix undefined tops ref in renumber
CI / test (pull_request) Successful in 42s
CI / docker (pull_request) Skipped
ec791cc2db
QA of the #167 follow-up found two defects:
1) renumber() referenced an undefined 'tops' variable in the rAF
   re-verification pass, so any wrap toggle that reflowed a partially
   filled last visual row left stale (non-idempotent) numbering.
2) rows were derived from per-span heights while the code column also
   renders newline text nodes between .codeline blocks, so the gutter
   could drift from the code column's real visual rows.

renumber() now measures each .codeline's actual offsetTop and places
every number on the visual row its line starts on (a line wrapping to N
rows gets its number on the first of them), pads filler rows in between,
and self-corrects one frame later if reflow moves any line. Wrap-OFF
path stays unchanged ('1
2
3
4'). Verified in headless Chromium:
gutter/code row alignment exact at 1200px and 640px, toggle cycles
stable, no horizontal scroll, no CSP console errors; go build/test pass.
Merge pull request 'Fix #167 r2' from fix-167-r2 into dev
CI / test (push) Successful in 42s
CI / docker (push) Successful in 39s
5c6cd40539
Fix #210: declare missing delete-button column in saved pastes table
CI / test (pull_request) Successful in 45s
CI / docker (pull_request) Skipped
8636a23f49
/mine rows render 7 cells (ID + delete button) but the colgroup and
thead only declared 6 columns, so under table-layout:fixed the delete
button cell overlapped the ID column at narrower widths. Add a
col-del column + empty header th to match the row cells.
Fix #209: move sort arrows to the right of the column label
CI / test (pull_request) Successful in 45s
CI / docker (pull_request) Skipped
5039a76bec
Fix #207 r2: dark mode toggle left aligned per owner feedback
CI / test (pull_request) Successful in 46s
CI / docker (pull_request) Skipped
c320fa03c9
Fix #205: strip whitespace-only text nodes between codeline blocks
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
5034f156ee
paste-lines.js rebuilt the codebody with innerHTML but relied on the
server-side '\n' delimiters disappearing between the per-line blocks.
Under white-space: pre any whitespace-only text node that survives
(cached HTML, template drift) renders as a phantom row and drifts the
gutter numbers off their lines. splitLines() now strips whitespace-only
text nodes after rebuilding, keeping renumber() geometry intact.
Fix #209 r2: arrows immediately right of label text, fixed gap
CI / test (pull_request) Successful in 44s
CI / docker (pull_request) Skipped
7cffd21df9
Absolute right:8px pinned arrows to the column edge; inline span after
the label with margin-left:6px keeps a consistent gap from the text.
Merge pull request #215 from fix-205
CI / test (push) Successful in 46s
CI / docker (push) Successful in 42s
13884ca786
Fix #205: stop gutter drift from phantom newline rows
Fix #209 r2: sort arrows immediately right of label text
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
89a9c173ca
Merge pull request #217 from fen/fix-209
CI / test (push) Successful in 41s
CI / docker (push) Successful in 37s
7c7e60375c
Fix #209 r2: arrows immediately right of the column label text
Fix details pill border clipped thin at corners (#222)
CI / test (pull_request) Successful in 42s
CI / docker (pull_request) Skipped
fa702eb8b1
The details pill drew its own 1px border with a 10px radius inside .float, which draws the real border at 20px radius and clips with overflow:hidden. The parent's looser curve clipped the pill's tighter corner curve, making the border appear thinner/cut at the corners, in both collapsed and expanded states. Drop the pill's own border/radius so .float is the single border surface, matching the other pills on the page.

Ref #222
fix #221: scale image pastes, drop text box, fix raw view and size
CI / test (pull_request) Successful in 45s
CI / docker (pull_request) Skipped
98ea7eefa9
- image pastes render the image scaled to fit the viewer box (aspect
  ratio preserved, max-height 70vh), no text/code box below it
- link pill moved under the image as a small inline chip
- /raw serves image attachment bytes as an image instead of empty text
- view details size reports the actual attachment file size
#221: summary pill size must come from the attachment blob for file pastes
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
d18bbb7064
The merged #224 fix covered the details grid but left the summary
pill using humanSize(len(row.Content)), which reads 0 for attachment
pastes (text content is empty). Use the attachment size there too.
#229: padding between image and pill border, drop corner-clipped inner border
CI / test (pull_request) Successful in 46s
CI / docker (pull_request) Skipped
86eb821780
#233: file attachment title takes the file name, fallback date.ext
CI / test (pull_request) Successful in 44s
CI / docker (pull_request) Skipped
785fafcaf9
#235: rename Language column to Type; attachment pastes show file extension
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
0008b8ce0c
- history/mine table column 'Language' -> 'Type' (data-sort key 'type')
- /api/public and /api/mine rows gain a 'type' field: file extension for
  attachment pastes, stored language otherwise (default 'text')
- paste page stats label 'Language' -> 'Type'; summary line uses the same
  label; get-paste JSON gains 'type'
- store list queries LEFT JOIN attachments to expose the filename
- table.js sorting accepts the 'type' key
#238: drop hardcoded page 2 from pagination window
CI / test (pull_request) Successful in 44s
CI / docker (pull_request) Skipped
b840bffeba
#240: keep submenu padding on burn-after-read row
CI / test (pull_request) Successful in 43s
CI / docker (pull_request) Skipped
f25ed8bc5d
#240: indent burn-after-read readable box under the option label text and match row padding rhythm
CI / test (pull_request) Successful in 44s
CI / docker (pull_request) Skipped
c89d064eb8
#243: copy button copies the paste link; content copy kept on separate button
CI / test (pull_request) Successful in 26s
CI / docker (pull_request) Skipped
1f745b6e59
Merge pull request '#243: copy button should copy the link' (#244) from fix-243 into dev
CI / test (push) Successful in 19s
CI / docker (push) Successful in 47s
3c5ccfb787
#243 fix attempt 2: capitalize action buttons; link button keeps its label after copy feedback
CI / test (pull_request) Successful in 20s
CI / docker (pull_request) Skipped
e7ecb9789b
v0.4.0 release prep: README refresh + new wiki screenshots (Ref #160)
CI / test (pull_request) Successful in 23s
CI / docker (pull_request) Skipped
7ee3ffbfc9
#243 pentest follow-up: reserve mine/unlock/guess/f custom slugs
CI / test (pull_request) Successful in 20s
CI / docker (pull_request) Skipped
ed22579bed
Merge pull request 'Reserve mine/unlock/guess/f custom slugs' (#247) from fix-reserved-slugs into dev
CI / test (push) Successful in 21s
CI / docker (push) Successful in 48s
CI / test (pull_request) Successful in 19s
CI / docker (pull_request) Skipped
cf6e52bcc5
fen merged commit 522e016a29 into main 2026-09-17 15:35:21 +00:00
Sign in to join this conversation.