Skip to content

feat(layer): add 'd' shortcut to toggle color mode#30

Merged
amondnet merged 2 commits into
mainfrom
feat/layer-toggle-color-mode-shortcut
May 28, 2026
Merged

feat(layer): add 'd' shortcut to toggle color mode#30
amondnet merged 2 commits into
mainfrom
feat/layer-toggle-color-mode-shortcut

Conversation

@amondnet
Copy link
Copy Markdown
Contributor

@amondnet amondnet commented May 28, 2026

개요

발송 마법사(Step1~5Controller)를 선택 단계화·건너뛰기 가능한 플로우로 재구성합니다. (Epic #107, 작업분해 E2-2-1)

변경 요지

  • SendStep enum 도입 — 정수 step 가드(1~5) 대체
  • Step1~5Controller 호출 사이트 enum 으로 전환
  • 신규 컨트롤러 3종 활성화 — Step2_5Controller(PDF), Step2_7Controller(등기자료), StepPhotoController(사진)
  • 기존 step_2_5.html/step_2_7.html mock 의 라우팅 채움 (DESIGN ONLY → routed)
  • 건너뛰기 동선(편지지·편지작성·사진) + 콘텐츠 0건 가드(주소 진입 시점)
  • AES WebView 브릿지 변경 0건 — PR 체크리스트로 회귀 차단

핵심 수용 기준 (이슈 #112 본문)

  • 편지지>편지작성>사진>PDF>등기자료>주소>결제 단계 구성
  • 각 단계 건너뛰기 (편지지/편지작성/사진)
  • WebView 에디터 브릿지 회귀 테스트 통과 (AES 메시지 프로토콜 웹/앱 동시 검증)
  • 기존 Step1~5Controller 의 역할을 단계화된 플로우로 전환

Spec / Plan

  • .please/docs/tracks/active/send-flow-stepwise-20260528/spec.md
  • .please/docs/tracks/active/send-flow-stepwise-20260528/plan.md

영향 모듈

  • mail-talk-web (SSR 컨트롤러·템플릿·서비스)
  • mail-talk-app (Flutter WebView 브릿지 — 회귀 검증만)

주의사항

⚠️ Constants.AES_KEY / AES_IV / channel callHandler 변경 0건. 본 PR 의 모든 reviewer 는 git diff 로 확인 필수.

Refs

  • Closes #112
  • Epic #107

Summary by cubic

Added a keyboard shortcut to toggle between light and dark mode. Press 'd' to switch. Configure via docs.shortcuts.toggleColorMode in app.config.ts (set to empty string to disable).

  • New Features
    • useDocsShortcuts composable using @vueuse/core onKeyStroke, installed via shortcuts.client.ts.
    • Default 'd' in app.config.ts and modules/config.ts; option schema in nuxt.schema.ts.
    • Ignores events when color mode is forced, a modifier key is held, or the target is editable (<input>, <textarea>, <select>, [contenteditable]).

Written for commit e8b70d2. Summary will update on new commits.


Verification Checklist

  • git diff origin/main -- mail-talk-app/lib/controller/letter/letter_step1_web_view_controller.dartAES_KEY/AES_IV/channel/callHandler 변경 0건
  • git diff origin/main -- mail-talk-app/lib/core/setting/constants.dart (또는 동등) — AES_KEY/AES_IV 상수 변경 0건
  • 모든 신규/변경 파일이 500 LOC 이하
  • Step5ControllerTest 기존 시나리오가 enum 전환 후에도 통과 (시그니처만 변경, 의미 보존)
  • 신규 컨트롤러 3종(Step2_5Controller, Step2_7Controller, StepPhotoController) 각각 MockMvc 권한/소유/UHL 가드 케이스 보유 (NewStepControllersTest)
  • Step4Controller 콘텐츠 0건 차단 케이스(AC-9) 포함 (NewStepControllersTest.Step4Tests)
  • step_1.html / step_2.html / step_photo.html 에 "건너뛰기" 버튼 + 다음 단계 URL 정확
  • 한국어 에러 메시지 노출 — "발송할 콘텐츠를 한 가지 이상 선택해 주세요."
  • Happy-path forward chain 확인 — moveStep3WithSave/editor/step_photo 로 redirect (편지작성 다음이 사진 단계)

Known Limitations / Follow-ups

  • Step1ControllerdefaultModelSetter 를 호출하지 않음 (pre-existing 설계, UHL 가드 미적용) — 별도 chore 권장
  • Flutter widget 회귀 테스트 미추가 — Flutter 코드 0줄 변경으로 정적 검증, 프로덕션 이슈 관찰 시 추가
  • moveStep3WithSave 함수명이 레거시 명명 잔재 — 후속 chore 에서 moveStepPhotoWithSave 등으로 rename 가능

Press 'd' to toggle between light and dark color modes. The shortcut
is configurable via app.config.ts (docs.shortcuts.toggleColorMode) and
can be disabled by setting it to an empty string.

The handler bails out when:
- the color mode is forced (colorMode.forced === true)
- the keystroke originated from an editable element (<input>, <textarea>,
  <select>, [contenteditable])
- any modifier key (meta / ctrl / alt / shift) is pressed

Reimplemented from upstream docus commit 61c36d03 (feat(layer): add d
shortcut to toggle color mode (#1377)) using @vueuse/core's onKeyStroke
instead of @nuxt/ui's defineShortcuts, since this project does not
depend on @nuxt/ui.

Refs: docs/docus-upstream-changes.md item #11
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces keyboard shortcuts configuration and implementation for the documentation layer, specifically adding a shortcut (defaulting to 'd') to toggle between light and dark color modes. The feedback suggests explicitly importing computed from vue to improve IDE support and unit testing compatibility, and refining the isEditableTarget utility to traverse up the DOM tree so that non-HTMLElement targets (like SVGs) inside editable containers do not unexpectedly trigger the shortcut.

Comment thread packages/layer/app/composables/useDocsShortcuts.ts
Comment thread packages/layer/app/composables/useDocsShortcuts.ts
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 5 files

Architecture diagram
sequenceDiagram
    participant User as End User
    participant Browser
    participant Nuxt as Nuxt App
    participant Vue as Vue Composition API
    participant ColorMode as @nuxtjs/color-mode
    participant DOM as DOM

    Note over User,DOM: Color Mode Toggle via 'd' Key

    User->>Browser: Presses 'd' key
    Browser->>DOM: keydown event

    DOM->>Vue: onKeyStroke listener (useDocsShortcuts.ts)
    Vue->>Vue: Check isEditableTarget(event.target)
    alt Editable element (input/textarea/contenteditable)
        Vue->>Vue: Bail out - ignore shortcut
    else Non-editable element
        Vue->>Vue: Check modifier keys (meta/ctrl/alt/shift)
        alt Modifier pressed
            Vue->>Vue: Bail out
        else No modifier
            Vue->>Vue: Check colorMode.forced
            alt forced === true
                Vue->>Vue: Bail out
            else not forced
                Vue->>Vue: Read toggleColorModeShortcut from appConfig
                alt Shortcut empty
                    Vue->>Vue: Bail out
                else Non-empty (default 'd')
                    Vue->>Vue: Read current colorMode.value
                    alt dark currently
                        Vue->>ColorMode: Set preference = 'light'
                    else light currently
                        Vue->>ColorMode: Set preference = 'dark'
                    end
                    ColorMode->>DOM: Apply CSS class change (light/dark)
                    ColorMode->>Browser: Persist preference (cookie/localStorage)
                    Browser-->>User: Visual theme toggled
                end
            end
        end
    end

    Note over Nuxt,Vue: Initialization (client-only)

    Nuxt->>Vue: Setup plugin (shortcuts.client.ts)
    Vue->>Vue: Call useDocsShortcuts()
    Vue->>Vue: Read appConfig.docs.shortcuts.toggleColorMode
    alt toggleColorMode defined
        Vue->>Vue: Register onKeyStroke listener
    else undefined
        Vue->>Vue: Use default 'd'
    end
Loading

Re-trigger cubic

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 28, 2026

Deploying docs-please with  Cloudflare Pages  Cloudflare Pages

Latest commit: e8b70d2
Status: ✅  Deploy successful!
Preview URL: https://78768df7.docs-please.pages.dev
Branch Preview URL: https://feat-layer-toggle-color-mode.docs-please.pages.dev

View logs

Applies feedback from gemini-code-assist review:
- Explicitly import `computed` from vue for IDE/test environments
- Traverse up the DOM in `isEditableTarget` so non-HTMLElement targets
  (SVGElement, MathMLElement) inside contenteditable containers are
  still treated as editable and do not trigger the shortcut
@sonarqubecloud
Copy link
Copy Markdown

@amondnet amondnet self-assigned this May 28, 2026
@amondnet amondnet merged commit 9df234a into main May 28, 2026
3 checks passed
@amondnet amondnet deleted the feat/layer-toggle-color-mode-shortcut branch May 28, 2026 15:56
amondnet added a commit that referenced this pull request May 28, 2026
Resolve modules-array conflict in packages/layer/nuxt.config.ts by
keeping both new module registrations from #29/#30/#31 and this PR's
markdown-rewrite module.
amondnet added a commit that referenced this pull request May 28, 2026
* feat(layer): add Vercel markdown-rewrite module

Adds a Nuxt module that injects Vercel build-output rewrite rules so
that AI agents (anything sending `Accept: text/markdown` or
`User-Agent: curl/*`) get served raw markdown instead of the SPA shell.

Behaviour:
- No-op on every non-Vercel preset (matches `vercel`, `vercel-edge`,
  `vercel-static`, etc. via `preset.startsWith('vercel')`).
- On Vercel: read `<output.publicDir>/../config.json`, validate that
  `llms.txt` was emitted, and unshift route pairs onto `routes` so
  they fire before the SPA fallback.
- Rules:
  - `/`         -> `/llms.txt`
  - `/<locale>` -> `/llms.txt`   (per `runtimeConfig.public.i18n.locales`)
  - `/<page>`   -> `/raw<page>.md` for every `/raw/...md` link found
    in `llms.txt`
- Vercel's `has` array is AND-ed, so OR semantics between the
  `Accept` and `User-Agent` matchers require emitting two rules per
  `src` -> `dest` pair.
- Locale codes are regex-escaped before being joined into the
  alternation so exotic codes can't break the pattern.

Ports upstream docus commits `6fd8686b` and `9ceafe6f` -- see
`docs/docus-upstream-changes.md` item #9.

Verification:
- `bun lint`        -> clean
- `bun typecheck`   -> no new errors in `markdown-rewrite.ts`
- `NITRO_PRESET=vercel bun --filter @pleaseai/docs-site build`
  injects two routes (homepage / Accept + User-Agent) into
  `.vercel/output/config.json`.
- Default (cloudflare) build is unchanged; module bails silently.

* fix(layer): apply review suggestions

Apply review feedback from cubic-dev-ai and gemini-code-assist on
the markdown-rewrite module:

- Read locale config from `nuxt.options.i18n` instead of
  `runtimeConfig.public.i18n` (matching the pattern used by the
  `nitro:config` hook in nuxt.config.ts). The i18n module does
  not always populate `runtimeConfig.public.i18n`, so the previous
  source could silently miss locale routes. (cubic)
- Decode the URL pathname with `decodeURIComponent` so that paths
  with URL-encoded characters (e.g. `%20`) match Vercel's router,
  which compares against decoded request pathnames. (gemini)
- Allow an optional trailing slash on docs page route patterns
  (`/?$` instead of `$`) so requests like
  `/en/getting-started/installation/` are matched consistently
  with the per-locale homepage routes. (cubic, gemini)

* Merge branch 'main' into worktree-agent-a1a3a89e87faf9e6d

Resolve modules-array conflict in packages/layer/nuxt.config.ts by
keeping both new module registrations from #29/#30/#31 and this PR's
markdown-rewrite module.
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.

1 participant