Template rendered 'action-fieldhidden' / 'link-fieldhidden' (no space) when
the hidden modifier applied, so:
- Tailwind .hidden class never applied -> Discord action card visible on
the new-link page's default Link tab
- JS querySelectorAll('.action-field') failed to match -> could not hide it
Root cause: '{% if %}...{% endif %}' directly appended to the class name
in link_form.html line 212. Verified via Playwright: new Link tab hides
action card, Action tab shows it, edit pages hide the wrong fields.
- markdown.css: .prose table gets display:block + overflow-x:auto so
wide tables scroll inside their own box instead of stretching the page
(post 2970 had a 1076px table overflowing 390px mobile and 1440px desktop)
- td gets word-break:break-word + overflow-wrap:anywhere for long URLs
- post_detail.html: .post-actions max-width:100% so Listen/Edit/Share/Delete
buttons wrap inside the container on narrow screens
- Revert TEMPLATE as separate LinkType; templates are plain links whose
URL contains {param} placeholders
- migration 0055: data-migrate any TEMPLATE links back to LINK, roll back
choices (0054 stays in history)
- link_form: back to 3 tabs (Link/Custom/Action); Link tab owns the URL
field plus a dashed '🔧 Add template parameters' toggle; the Sketch
builder auto-shows when the URL contains { } (and stays visible after a
manual toggle); hidden on Custom/Action tabs
- badges (row/detail/search) detect templates by URL content again;
detail page shows Original URL for plain links
- views/forms: drop is_template plumbing and TEMPLATE validation
- models: LinkType gains TEMPLATE (migration 0054, choices only)
- link_form: 4 tabs — Link / 🔧 Template / Custom / ⚡ Action; each type
shows only its own fields: Template tab owns the Sketch builder, Link tab
is a plain URL, Custom owns the markdown editor, Action owns the Discord
card + message template; per-type descriptions; tab colors blue/purple/
green/purple
- Editing a legacy LINK with {param} in URL auto-switches to Template tab
(and saving migrates it to TEMPLATE type)
- badges (row/detail/search cards) recognize TEMPLATE type; detail page
shows Original URL for TEMPLATE too
- forms: TEMPLATE requires original_url
- Fix Uncaught ReferenceError: tbody is not defined — the client-side filter
rewrite dropped the const tbody declaration still used by load-more
- Mobile: Delete Selected becomes a sticky frosted bottom bar (safe-area
aware); disabled (grayed) until a row is selected, then red
- Mobile: library search input full-width 48px (primary interaction)
- Default list: 20 rows (was 50) sorted by updated_at desc (recent first)
instead of click_count; load-more keeps paging +20
- Command palette (Ctrl/Cmd+K or nav search icon): /search/palette/ groups
links/pages/posts with jump/detail/edit actions, keyboard navigation
- Hero: stats inline under search pill, ⌘K chip on desktop, Random Images
broken-image fallback to elegant SVG placeholder (layout untouched)
- Restore original green nav (bg-custom-blue). The frosted-glass nav from
1.0.401 broke the mobile Menu dropdown: backdrop-filter creates a
containing block, collapsing the fixed full-screen dropdown to 3px
- Palette tests: +5 cases (grouping, post match, management fields,
empty query, no results)
- /search/aliases/ now matches alias/url/description/text/tags and returns
id, link_type, detail_url, edit_url, click_count for management actions
- Library filter upgraded from client-side row filtering to live search
cards: click card -> detail page, inline edit/delete, alias jumps
- Mobile: table rows render as cards (kills 620px horizontal scroll),
hidden cells stay hidden, no viewport overflow
- Hero search no longer autofocuses on touch devices (no keyboard pop);
desktop keeps autofocus via hover:fine media query
- Nav bar unified to light frosted-glass (was dark green) across all pages
- Fix hero-glow decorative overflow on mobile
- Add tests/test_search_aliases.py (8 cases)
Root cause of the squashed chart: canvas had a fixed height=90 attr and no container, so on narrow viewports Chart.js compressed everything — legend overlapped the plot, x labels tilted 45deg, y ticks degenerated (-1000% scale). Fix: relative h-72/h-80 container + maintainAspectRatio:false, grace 5%, maxTicksLimit, maxRotation:0, smaller points (r2/1.5), compact legend/tooltip, Chinese help text.
- Add django.contrib.humanize; apply intcomma to every currency amount across invest templates (dashboard, portfolio detail, transactions)
- get_risk_summary now aggregates top_positions by ticker (MRVL across MOMO+IBKR merges into one row with Accounts column), keeping Top 1/3/5 cards and table on the same basis
- Mobile: metric cards all 2-col (2x2 + 2+1 with Last Snapshot spanning full width), no more 1-col break
- Transactions show source badges: purple 🤖 AI (source ai/ocr), grey 手动, amber ⚠ 低置信 when confidence < 0.9
- Delete unused invest/base.html (dead nav; page extends GoLinks base.html)
- tailwind.config.js: add invest/jbot/routermon template dirs so their classes are scanned (text-[10px] etc. were silently missing)
- New /ui/files/{pk}/thumb/ endpoint: Pillow resize for images, ffmpeg first-frame for videos, disk-cached with per-record lock
- Grid & carousel render server thumbnails via <img> — fixes blank video thumbs on iOS Safari
- Carousel upgraded to 3D cover-flow: perspective rotateY/scale/opacity driven by scroll position
- Preview <video> gets playsinline + webkit-playsinline — fixes close button unusable after iOS fullscreen playback
- thumbnail_url exposed in serializer, upload response, and client JSON
- 3 new tests: thumb 200/cache, non-media 404, missing-file 404
- Three layouts: list (unchanged) / grid / carousel, persisted in localStorage
- Grid: image thumbnails (lazy), video first-frame + play badge, doc icon fallback
- Carousel: scroll-snap horizontal track, desktop arrows, native swipe on mobile
- Click any card opens the existing preview modal (with prev/next navigation)
- Mobile-first: 2-column grid on phones, hidden carousel arrows on touch
- Pure frontend in list.html; no model/API changes
- template-description box was shown on Action tab (JS never controlled it)
- Message preview now renders as a Discord-style chat bubble (avatar, author,
dark background) with {query} highlighted as a chip
- Hide action_config JSON field from the form (internal storage, not user-editable)
- Replace Action dropdown with an Apple-style radio card (💬 发消息到 Discord)
- Rename Message template → 消息内容 with plain-language help text
- Add live message preview that highlights {query} as a chip
- Tests: edit page renders card + Chinese labels, no JSON exposed (109 passed)
link_detail.html and _link_row.html only handled Template/LINK types,
so ACTION links fell through to the Custom badge. Add badge-action
branch + CSS so go/link/235/ (alias=ask) displays Action, matching the
Action tab in the link form.
Prod had an old ask link (LINK → chatgpt.com, id=235). get_or_create
would leave it as LINK, so go/ask/问题 would redirect to chatgpt instead
of sending to Discord. Switch to update_or_create and back up the old
chatgpt link to alias ask-chatgpt.
Remove hardcoded /ask/ routes (core/urls.py), /api/ask/ (api_urls.py),
ask_views.py, and ask.html input page. Ask is now a normal Link record
(alias='ask', link_type=ACTION) created by data migration 0053, so it
behaves exactly like other action links: go/ask/问题 → catch-all →
execute_action → 302 to Discord, editable/deletable in the Links UI.
Tests updated: ask covered as ACTION link (redirect/dedup/empty-query).