Skip to content

Test#2

Open
Hackin7 wants to merge 182 commits into
Hackin7:replace-sliderfrom
AdvisorySG:main
Open

Test#2
Hackin7 wants to merge 182 commits into
Hackin7:replace-sliderfrom
AdvisorySG:main

Conversation

@Hackin7

@Hackin7 Hackin7 commented May 23, 2022

Copy link
Copy Markdown
Owner

No description provided.

wei2912 and others added 30 commits May 14, 2022 17:19
This commit also replaces OWL Carousel with GliderJS.
All templates other than index.hbs will continue to use meta_title as the
title, while index.hbs will use "Stories".
* fix: [#27] Optimize h1 font size in utils.css

* [#79]: Make tags shown on index and tag consistent
* Quotes slider with bullets
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 10.4.4 to 10.4.7.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](postcss/autoprefixer@10.4.4...10.4.7)

---
updated-dependencies:
- dependency-name: autoprefixer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.12 to 8.4.14.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.4.12...8.4.14)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [gscan](https://github.com/TryGhost/gscan) from 4.26.1 to 4.31.0.
- [Release notes](https://github.com/TryGhost/gscan/releases)
- [Commits](TryGhost/gscan@v4.26.1...v4.31.0)

---
updated-dependencies:
- dependency-name: gscan
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [gscan](https://github.com/TryGhost/gscan) from 4.26.1 to 4.31.2.
- [Release notes](https://github.com/TryGhost/gscan/releases)
- [Commits](TryGhost/gscan@v4.26.1...v4.31.2)

---
updated-dependencies:
- dependency-name: gscan
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [@tailwindcss/line-clamp](https://github.com/tailwindlabs/tailwindcss-line-clamp) from 0.3.1 to 0.4.0.
- [Release notes](https://github.com/tailwindlabs/tailwindcss-line-clamp/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss-line-clamp/blob/master/CHANGELOG.md)
- [Commits](tailwindlabs/tailwindcss-line-clamp@v0.3.1...v0.4.0)

---
updated-dependencies:
- dependency-name: "@tailwindcss/line-clamp"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [cssnano](https://github.com/cssnano/cssnano) from 5.1.7 to 5.1.12.
- [Release notes](https://github.com/cssnano/cssnano/releases)
- [Commits](https://github.com/cssnano/cssnano/compare/cssnano@5.1.7...cssnano@5.1.12)

---
updated-dependencies:
- dependency-name: cssnano
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
* fix inconsistent fonts and spacing for tagless post

* Update post-card.hbs

Co-authored-by: Terence Chan Zun Mun <zunmun@gmail.com>
Bumps [gscan](https://github.com/TryGhost/gscan) from 4.31.2 to 4.32.0.
- [Release notes](https://github.com/TryGhost/gscan/releases)
- [Commits](TryGhost/gscan@v4.31.2...v4.32.0)

---
updated-dependencies:
- dependency-name: gscan
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [husky](https://github.com/typicode/husky) from 7.0.4 to 8.0.1.
- [Release notes](https://github.com/typicode/husky/releases)
- [Commits](typicode/husky@v7.0.4...v8.0.1)

---
updated-dependencies:
- dependency-name: husky
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [gscan](https://github.com/TryGhost/gscan) from 4.32.0 to 4.33.0.
- [Release notes](https://github.com/TryGhost/gscan/releases)
- [Commits](TryGhost/gscan@v4.32.0...v4.33.0)

---
updated-dependencies:
- dependency-name: gscan
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
AA2409 and others added 7 commits November 19, 2025 09:00
* Update footer.hbs

* Update post.hbs
* Update footer.hbs

* Update page-team.hbs

* fix: team page height entry fix

---------

Co-authored-by: Terence Chan Zun Mun <zunmun@gmail.com>
Ubuntu version is fixed to LTS 24.04, consistent with production.
teyyyyy and others added 3 commits June 8, 2026 00:29
…ws (#483)

* docs(specs): add sort/filter design for events and interviews

Captures the brainstorming output for two features (overview index) and
the full design spec for Feature 1 — multi-tag client-side filtering on
the /events/ and /interviews/ collections, with URL sync and
load-more pagination.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plans): add implementation plan for events/interviews sort+filter

Twelve-task TDD-light plan derived from
2026-05-06-sort-filter-design.md, covering Alpine component, partial,
template wiring, routes update, accessibility, SEO canonical,
graceful-degradation and final scenario sweep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(post-card): expose public tags via data attributes

* fix(post-card): pipe-separate tag names, single-quote visibility arg

* feat(js): add postFilterList Alpine component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(filter): single DOM walk and document component contracts

* feat(events): add multi-tag filter and load-more

* fix(filter): hoist x-cloak to utils, doc isVisible contract, limit=all

* feat(interviews): add filter using shared partial

* fix(filter): align template filter strings with routes.yaml tag variants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(templates): doc filter sync with routes; degenericise index.hbs

* fix(filter): a11y checkmark, scoped tabindex, empty-state clear button

* docs(specs): add search/sort/full-load design for events and interviews

Extends the prior tag-filter feature with: Typesense-backed search,
4-option sort dropdown, and approach-A template pagination (20 blocks,
2000 ceiling) to fix the limit='all' cap at 100 posts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plans): add implementation plan for search/sort/full-load

9 tasks ordered: full-corpus load (1) → sort (2-4) → search (5-8) →
end-to-end verification (9). Each implementation task ends with build,
gscan lint, manual browser check, and commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(filter): full-corpus load via 20 stacked {{#get}} page blocks

* docs(filter): preserve focus rationale + clarify Ghost's 100/page max

Re-add the comment explaining tabindex="-1" enables loadMore() focus
(lost during the sub-partial extraction) and document that limit=100
is Ghost's per-page cap, not an arbitrary choice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(post-card): expose slug, title, published-at as data attributes

* feat(filter): add client-side sort with URL sync

* refactor(filter): hoist VALID_SORTS, document _reorderDom parent assumption

Hoist the four-mode allowlist to a module constant so the URL parser,
the dropdown UI (Task 4), and the sort comparator share one source of
truth. Document the implicit single-parent assumption in _reorderDom
so a future partial split won't silently re-parent cards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(filter): add sort dropdown to toolbar

* style(filter): align toolbar bottom-margin with chip row (mb-4 -> mb-6)

Match the established mb-6 cadence used by the chip row directly below.
Keeps vertical rhythm consistent now that toolbar precedes chips.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(search): add Typesense search wrapper

* feat(filter): thread page tagSlugs into Alpine component for search scoping

* docs(filter): document tagSlugs/filter mirror requirement

The slug list now appears in two formats per page (Ghost filter syntax
+ plain comma-separated). Comment explains the constraint so future
edits don't drift one without the other.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(search): integrate Typesense search into filter pipeline

* fix(search): prevent isSearching flicker, abort on clearFilters

Two correctness fixes surfaced in code review before Task 8 wires the UI:

1. _runSearch now captures the AbortController locally so finally{} only
   clears isSearching when THIS call is still the latest. Otherwise rapid
   typing makes the spinner flicker off when the aborted call's finally
   fires while the superseding call is still in flight.

2. clearFilters now aborts any in-flight search, clears the debounce
   timer, and forces a URL write. Without this, a stale Typesense
   response could land after the clear and re-populate searchSlugs,
   and ?sort= or ?q= could linger in the URL when their watchers
   weren't dirty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(search): add search input, indicator, banner, and empty-state adaptation

* fix(search): inline min-width, drop redundant Esc refocus, unify ellipsis

Tailwind 3.0 JIT in this project doesn't reliably emit arbitrary
values like min-w-[200px], so the toolbar would have collapsed below
the intended threshold on narrow viewports. Inline style guarantees
the constraint regardless of the JIT scan.

Also: $event.target.focus() in the Esc handler is a no-op (the input
already has focus when Esc fires) — drop. And use the U+2026 ellipsis
in the placeholder to match the Searching… indicator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(filter): close UX gaps from final review (Esc lag, stale URL, DRY)

Four cleanups from the whole-branch review:

1. setSearchQuery short-circuits to immediate _runSearch when input is
   empty/sub-threshold. Previously Esc-to-clear left the URL ?q= and
   result count stale for the full 250ms debounce window.

2. init() normalizes sub-threshold ?q= values to '' so a hand-crafted
   /events/?q=x doesn't sit in the input with no active search behind it.

3. New hasActiveFilters() getter consolidates the
   "tags || search || sort != newest" expression that had been
   duplicated in three x-show bindings.

4. Refresh stale "Not consumed in Task 3" comment on the tagSlugs
   constructor parameter — now describes its actual role (Typesense
   filter_by scoping).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(search): move Typesense config to package.json config.custom

Three Typesense settings (host, api_key, collection) move from JS-file
constants to package.json config.custom defaults, admin-overridable in
Ghost → Design → Customize. default.hbs injects the resolved values
into window.__TYPESENSE_CONFIG__ before the bundle loads, and the
wrapper reads from there at search time (with the same defaults as
fallback for partial-page-render contexts).

Operationally: deploying to a different Ghost instance no longer
requires editing the theme — admins point the search at their own
Typesense backend via the Customize panel. The API key remains
search-only by design (read-only, public-scoped).

Adds a "Typesense Search" section to README documenting the three
settings and the security model of the embedded key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: base dropdown

* feat: make it look nicer

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(specs): add targeted related-posts design

Replaces the bottom-of-article widget's "any shared tag" matching
with Typesense semantic ranking on title+excerpt, with the existing
tag-matched SSR rendering serving as both the no-JS fallback AND the
topup pool when Typesense returns < 3 hits. Cross-collection scope.
3-card layout preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plans): add implementation plan for targeted related-posts

8 tasks: Typesense plumbing (config + wrapper), post-card data-slug,
Alpine component with card builder, partial wrapper changes, main.js
registration, README, end-to-end manual verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(config): add Typesense config to package.json + default.hbs

* feat(search): add Typesense searchSimilar wrapper

* feat(post-card): expose slug as data attribute for related-posts JS

* feat(related): add Alpine component with Typesense fetch + card builder

* fix(related): self-exclusion uses id, document post-card divergences

Three cleanups from code review of Task 4:

1. The defensive filter dropping the source post compared h.slug to
   source.id — different value spaces (slug vs ObjectId hex), so the
   guard was dead code. Add 'id' to Typesense include_fields and
   compare on h.id, restoring the safety net the comment claimed.

2. Document the two intentional divergences from post-card.hbs in the
   buildCardElement comment block: hardcoded "feed-card post" instead
   of {{post_class}} (verified safe — no CSS targets per-post tag-{slug}
   classes), and omitted <img> when feature_image is empty (post-card
   uses a hidden placeholder; both are display:none).

3. pickPrimaryTag drops the type-confusing "|| hit.tags" fallback —
   tags.name is always requested in include_fields so the fallback
   couldn't help, and hit.tags has a different shape that would make
   names[i] return an object instead of a string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(related): wrap with Alpine component, source data on data-attrs

* feat(related): register relatedPosts Alpine component

* docs(readme): document Typesense search configuration

Adds a new section explaining the three custom-config fields, the
search-only key security model, and where to override per-install.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(post-card): cross-reference the JS card builder mirror

Final-review item: makes the JS↔HBS mirror contract discoverable from
the HBS side. A future contributor changing post-card.hbs now has a
breadcrumb to assets/js/related-posts.js → buildCardElement().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(related): exclude self by id AND slug, in case one identifier is empty

User reported the recommended-articles widget was including the article
itself. Live verification of Typesense's filter_by=id:!=X showed it
works correctly, so the bug must be on our side: source.id from
data-post-id="{{post.id}}" was likely empty for some reason, making
the wrapper's `if (excludeId)` gate skip the filter, AND making the
JS defensive filter useless (h.id !== '' is always true).

Three layers of defense added:

1. Partial now exposes data-post-slug="{{post.slug}}" alongside
   data-post-id. Slug is the most reliable identifier (also in the
   page URL and on every post-card).

2. typesense-search.js gains an excludeSlug option. When both are
   passed, filter_by combines them with && so a doc matching either
   identifier is excluded server-side.

3. JS defensive filter now checks id, slug, AND url — any one match
   triggers exclusion. Empty source identifiers are skipped (no false
   positives where empty string matches empty field).

Verified live: filter_by=slug:!=X excludes the named post correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(related): rewrite Typesense URLs to current origin (no more cross-site jumps)

Typesense indexes posts with production-absolute URLs
(https://advisory.sg/...). The JS card builder consumed hit.url verbatim
for both the inner div onclick and the stretch-link href, so clicking a
related card on localhost:2368 navigated the user OFF-SITE to the prod
domain. SSR cards were already correct because Ghost's {{url}} helper
resolves against @site.url.

Add a toLocalPath() helper that returns just pathname+search+hash from
any URL (absolute, relative, or malformed). The browser then resolves
the result against the current page's origin: localhost stays on
localhost, prod stays on prod, no environment-specific config.

Apply at three sites: the onclick interpolation, the stretch-link href,
and the defensive self-exclusion URL check (which previously compared
full URLs and never matched on localhost — now compares paths).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.