Root cause: large-title rehydrate was reusing the remote tx’s
original entity id. When that id was a string tempid,
Datascript had already resolved it during remote apply, so rehydrate
created a new invalid entity with only :block/title.
Make `:ref/default-open-blocks-level 0` collapse references by default
in the DB version, matching the previous file-graph behavior. The
section fold is scoped to the page-bottom "Linked References" panel
only — the inline "Open block references" popup rendered next to
blocks always shows its references uncollapsed.
1. Collapse the "Linked References" section when the configured level
is 0, gated on a new `:linked-refs-section?` config flag set only
by the page-bottom call site in page.cljs. The inline popup at
block.cljs:3366 passes `{}` and is unaffected.
2. Propagate `:block.temp/has-children?` on the top-level fetched
block in `get-block-and-children`. The list-view loads linked-
reference blocks with `:children? false`, so `(:block/_parent ...)`
is always nil in the client DB and the collapse check in
`block-default-collapsed?` could never fire. Use a lightweight
`d/datoms :avet :block/parent` scan that stops at the first match,
rather than the reverse-ref `(:block/_parent block)` which
materializes the full child set. Includes a regression test.
3. Fall back to `:block.temp/has-children?` when computing `has-child?`
in `block-container-inner-aux`. This renders the collapse arrow for
blocks whose children exist in the worker DB but haven't been
lazily loaded into the client DB yet (e.g. linked-reference blocks).
Clicking the arrow calls `expand-block!` which loads them.
The `:ref/default-open-blocks-level 0 → (int? ...)` state.cljs fix
from PR #12228 is already present on this branch.
Move the Logseq Markdown Mirror syntax/export work out of the two-way sync branch while leaving file-to-DB sync behavior behind.
Details:\n- add docs/logseq-markdown-syntax.md and update ADR 0016 with the one-way mirror syntax contract\n- export mirror files with page id markers, property list items, nested default property values, node page refs, task status markers, and datetime values with time\n- preserve block refs as uuid links where needed while keeping page/node refs readable\n- update focused export and markdown mirror tests
Validation:\n- bb dev:lint-and-test
Adds a Fallback dimension to avatar icons (:letters | :icon) with
inheritance through `:logseq.property.class/default-icon`. When the
fallback is :icon, the avatar renders the chosen tabler icon instead
of initials, color-inheriting from the contrast-adjusted muted tint.
Highlights:
- normalize-icon enforces an invariant on both fast and slow paths:
a :fallback-type :icon without a non-blank :fallback-icon degrades
to :letters, so the renderer never has to guard.
- get-node-icon extends class-default select-keys to propagate
:fallback-type and :fallback-icon alongside :shape.
- Both the text-only avatar branch and avatar-image-cp dispatch on
:fallback-type. Tabler icons render at ~55% of avatar size with
the fallback's contrast-adjusted color.
- New Fallback row in the customize band with a ghost-chip dropdown.
Selecting "Letters" commits inline; selecting "Icon…" opens a
constrained sub-picker (only the Icons tab) anchored on the click.
- Generic addition: icon-search now accepts an :allowed-tabs prop
that filters the tab strip and seeds *tab to the first allowed
entry. Useful beyond fallback (any caller wanting a scoped picker).
- Reset link now clears Shape AND Fallback together, dropping any
dormant :fallback-icon. Disabled when state matches default.
Polish:
- Avatar font-size scales up past 32px (16px @ 40px tile, 22px @ 56px
tile, ~40% of size for larger). Page-icon and band preview now
read as proper avatars instead of small text in big circles.
- Customize band labels match Settings panel style (text-sm
font-medium leading-5 opacity-70).
- preview-meta gets min-height: 56px + justify-content: center so
the resting "Title / subtitle" sits centered against the avatar.
- Ghost-chip aesthetic: dropdown chips drop background and border at
rest (1px transparent border keeps geometry stable), revealing
fill on hover and Radix's data-state="open". Label and value share
the same 14px text-sm so each row reads as one "Shape: Circle"
line — Linear/Notion settings panel register.
- Tighter row geometry: 26px chip × 2 + 4px gap = 56px exact match
against the avatar tile. No more overflow tail under the avatar.
Tests: 16 new assertions across 6 deftest groups (legacy default,
round-trip, :icon→:letters degradation, blank-icon edge case,
top-level legacy keys, full multi-field coexistence). 26 total
icon test assertions, all passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a Shape dimension to avatar icons (circle | rounded-rect) with
inheritance through `:logseq.property.class/default-icon`. Surfaced via
a tap-the-preview customize band in the asset-picker (avatar mode) with
a Shape dropdown and a keymap-style Reset/Done rail. Animates open/close.
Highlights:
- normalize-icon defaults `:shape :circle` for legacy data on both the
slow path and the already-shaped fast path.
- get-node-icon extends class-default `select-keys` to propagate :shape.
- avatar.tsx accepts `data-shape`; CSS in icon.css drives the radius via
`[data-shape="rounded-rect"]` selectors (avoiding Tailwind JIT issues
with conditional arbitrary-value classes).
- Customize band: preview tile + Shape dropdown + Reset/Done rail. All
blocks always rendered so CSS transitions can interpolate height,
gradient, and the cue badge crossfade. Layout matches Paper artboard
99K-1 / 97A-1 (344px inner content inside 380px band, inset rail
separator, gradient flush against topbar).
- Fixes `keep-popup?` plumbing at three forwarding wrappers (asset-
picker, icon-search, icon-picker) and the topmost on-chosen handler
in property/value.cljs. Single click now produces a single write
instead of the prior triple-write race.
- icon-row (property/value.cljs) and icon-search (icon.cljs) both made
reactive via model/sub-block — so in-popup commits update the picker
preview/chip live, not just the page-header avatar.
- Lazy `*text-measure-ctx` so the namespace loads in the Node test
runner (was previously blocking all icon tests).
- New `.lx-toolbar-action` / `.lx-toolbar-reset-link` utility CSS
mirrors Settings → Keymap shortcut popover footer styling.
- 10 new test assertions for shape default, preservation, fast-path
handling, and field independence.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds an icon prefix to the Name cell of class-instance tables and a
batch Set icon button to the row-selection action bar. Avatar/text
initials are derived per row, so batch-applying an avatar to multiple
rows yields each row's own initials while preserving picker colors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Avatar fallback rendering: replace the prior 31.4%-alpha background
treatment, which silently rendered dark picks (#1a3d60 etc.) at ~1.1:1
contrast on dark surfaces. The new pipeline computes a hue-preserving
muted tint for the bg via OKLCh L bisection (~1.5:1 vs page surface)
and runs the picked color through adjust-for-contrast (3.0 target) for
the initials. Picked color passes through as text whenever it reads;
only genuinely-illegible picks get lifted, and the lift stays close
to the picked hue. Works for both custom hex picks and Radix theme
tokens (var(--rx-...)) via a new colors/->hex CSS-color resolver.
The 3.0 target — instead of WCAG 4.5 body-text — treats avatar initials
as decorative identifiers (matches Slack/Linear/GitHub practice) and
lets vivid hues like tomato and red pass through without desaturating.
Class default-icon row: new property row that uses the unified icon
picker in default-icon mode, where Text/Image tiles commit immediately
rather than drilling into sub-pickers (per-instance inheritance derives
the actual face from each instance's title). Setting a class's page
icon now auto-syncs into default-icon when default-icon is empty so
instances inherit it; clearing the page icon only clears default-icon
if the two were synced.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The floating URL+Upload buttons are the last UI in the picker still
pushing users toward an explicit URL-name dialog; paste and Web Image
flows already auto-derive names. Replace them with a thin static
footer ("Tip: Drop an image, paste a link, or browse · ⌘V"), delete
the url-asset-pane popover entirely, and fix URL-paste naming to use
extract-filename-from-url instead of clipboard-{timestamp}. Phones
get a parallel hint where each verb is a real control (iOS Safari
won't deliver paste events to non-input popover roots).
Also: title+caption styling for the Wikipedia tooltip to match the
color-picker contrast tooltip, and remove the 56px grid bottom
padding that previously cleared the floating bar.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The icon-picker's color swatch only lived at level 1 — to recolor an
avatar from inside the asset-picker the user had to click Back, recolor,
then drill into Custom > Avatar again. Surface the same trigger in the
asset-picker topbar so the round trip collapses to one click.
- Trigger renders only when mode = :avatar; image assets aren't tinted
so showing it in Image mode would be misleading. Toggling segment to
Image dismisses an open color popover by id (:asset-picker-color) so
it doesn't orphan over an unrelated topbar.
- The color-picker component itself is unchanged besides accepting an
optional :popup-id opt and threading it into shui/popup-show!. The
asset-picker observes the same `*color` rum atom the icon-picker
topbar uses, so backing out reflects the new color in the parent
immediately — no state duplication.
- Hover-preview wired through preview-target-db-id, same as the parent.
- Layout: bundles color + trash inside `.asset-picker-topbar-actions`
in the topbar's right grid cell. Class is intentionally distinct from
`.asset-picker-actions` (the floating bottom bar with "Add image via
URL" / "Upload image"); reusing the latter would inherit its
`position: absolute; bottom: 0` and yank the topbar group off-screen.
Forward-declares `color-picker` near the asset-picker so the
top-to-bottom CLJS compile resolves the call site at line 3375 even
though the definition lives at line 5042. Without the declare, CLJS
emits a direct property reference that's undefined at runtime, the
`(color-picker …)` call throws, and the entire `.asset-picker-topbar-
actions` subtree fails to mount (which manifested as both the color
trigger AND the trash going missing).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds four asset-scoped properties so Logseq can keep the provenance of an
image alongside the file:
- :logseq.property.asset/source-url — Wikimedia descriptionurl, Wikipedia
page, or any user-supplied source link. Queryable; this is the join
key the asset-picker uses to dedup web-image hits against the local
library.
- :logseq.property.asset/source-name — short label ("Wikimedia Commons",
"Wikipedia", etc.). Queryable.
- :logseq.property.asset/license — license slug (CC-BY-SA-3.0 etc.).
Queryable.
- :logseq.property.asset/attribution — full credit string for embed/
export contexts. Not queryable.
Schema bumped 65.26 → 65.29 with three migrations:
- 65.27: register the four new properties.
- 65.28: an in-development DB hit a build that registered source-url
with :type :url (a ref-typed schema), which made datascript treat
plain URL strings as tempid lookups and blocked every asset save with
"Tempids used only as value in transaction". Coerces the entity's
:logseq.property/type back to :string.
- 65.29: 65.28 corrected the type but left :db/valueType :db.type/ref on
the same entity. In Logseq's datascript fork the :db/valueType on a
:db/ident-keyed entity IS the live schema, so the attribute stayed
ref-typed and string URLs continued to fail. Retracts :db/valueType
to release the lock; mirrors logseq.outliner.property's existing
ref→non-ref pattern.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Keep editor async tests pinned to their test graph and restore frontend state so full cljs:run-test order does not leak into persist-db tests.
Issue: https://github.com/logseq/db-test/issues/821
Fixes rapid Enter then Tab applying indentation to the previous editing block while the newly inserted block is still pending.
fixes https://github.com/logseq/db-test/issues/821
Store only the latest non-empty server :block/title conflict for a block, clearing previous title conflict candidates before inserting the new one.
Add a regression test covering previous title candidates, empty server titles, and the latest non-empty title.
Normalize browser asset paths through the same memory URL flow used by renderer asset IO so graph names with spaces resolve correctly during RTC upload.
Handle async asset read failures in upload as read-asset failures, and surface queued asset uploads plus active asset upload/download counts in the RTC indicator.
Tests cover browser asset path normalization and RTC asset transfer summaries.
Add markdown mirror generation for DB graphs, including page and journal paths, regeneration, debounced write handling, and settings UI.
Serialize page and block property values into mirrored Markdown by resolving property-value entities to their display content.
Persist mirror files through the node worker platform and make browser worker mirror storage fail fast as unsupported.
Fix Electron userAppCfgs writes to avoid returning unserializable Electron state over IPC.
Add ADR and targeted tests for mirror generation, worker wiring, platform storage, and graph path handling.