From c0af5fa7b4001641d1ff44e2229b08872b047af4 Mon Sep 17 00:00:00 2001 From: Kevin Deng Date: Thu, 20 Aug 2026 19:59:57 +0900 Subject: [PATCH] Replace platform emoji flags with consistent SVG region flags (#30) --- app/components/CharTable.vue | 6 +++--- app/components/FilterBar.vue | 12 +++++++----- app/components/HeroOverprint.vue | 9 +++++---- app/components/OptionsMenu.vue | 16 ++++++++-------- app/components/RegionLabel.vue | 20 ++++++++++++++++++++ app/composables/prefs.ts | 29 +++++------------------------ app/locales/ja-jp.ts | 4 ++-- app/locales/ko-kr.ts | 4 ++-- app/locales/zh-cn.ts | 4 ++-- app/locales/zh-hk.ts | 4 ++-- app/locales/zh-tw.ts | 4 ++-- app/pages/char/[key].vue | 24 +++++++++++------------- app/styles/global.css | 14 +++++++------- public/flags/LICENSE.md | 21 +++++++++++++++++++++ public/flags/cn.svg | 1 + public/flags/hk.svg | 1 + public/flags/jp.svg | 1 + public/flags/kr.svg | 1 + public/flags/tw.svg | 1 + 19 files changed, 102 insertions(+), 74 deletions(-) create mode 100644 app/components/RegionLabel.vue create mode 100644 public/flags/LICENSE.md create mode 100644 public/flags/cn.svg create mode 100644 public/flags/hk.svg create mode 100644 public/flags/jp.svg create mode 100644 public/flags/kr.svg create mode 100644 public/flags/tw.svg diff --git a/app/components/CharTable.vue b/app/components/CharTable.vue index 52554d6..40f77cc 100644 --- a/app/components/CharTable.vue +++ b/app/components/CharTable.vue @@ -3,7 +3,7 @@ import { injectChars } from '~/composables/chars.ts' const chars = injectChars() const { t } = useT() -const { regionLabel, labelClass, visibleRegions, columnTracks } = usePrefs() +const { flagsOn, visibleRegions, columnTracks } = usePrefs() const scrollToTop = useScrollToTop() const list = ref() @@ -26,8 +26,8 @@ function turnTo(page: number) { :key="region" class="text-center eyebrow !text-$c-ink-soft" :title="t(`region.${region}.full`)" - >{{ regionLabel(region) }} + > {{ t('table.strokes') }} - {{ regionLabel(form.region) }} + diff --git a/app/components/OptionsMenu.vue b/app/components/OptionsMenu.vue index fd216e7..f07fa88 100644 --- a/app/components/OptionsMenu.vue +++ b/app/components/OptionsMenu.vue @@ -2,10 +2,9 @@ import { localeName, type Locale } from '~/locales/index.ts' const { t } = useT() const { - emojiFlags, + flagLabels, + flagsOn, outline, - regionLabel, - labelClass, COLUMNS, columnShown, columnLocked, @@ -16,7 +15,7 @@ const languages = locales.map((code) => ({ code, label: localeName(code) })) /** Reader preferences, each labeled by `options.` and `Hint`. */ const options = [ - { key: 'emoji', model: emojiFlags }, + { key: 'flags', model: flagLabels }, { key: 'outline', model: outline }, ] @@ -93,7 +92,7 @@ onKeyStroke('Escape', () => (open.value = false)) on, so selection is a filled slab. Here an enabled column is the normal state (except Korea, which starts off), so a chip that is off simply fades. That also keeps a solid ink field from landing behind - a flag, where the emoji's own colors fight it. + a flag, where the artwork's own colors fight it. -->
{{ @@ -122,9 +121,10 @@ onKeyStroke('Escape', () => (open.value = false)) :aria-pressed="columnShown(column)" @click="toggleColumn(column)" > - {{ - regionLabel(column === 'old' ? 'jp' : column) - }} + {{ t('region.old.short') }}
diff --git a/app/components/RegionLabel.vue b/app/components/RegionLabel.vue new file mode 100644 index 0000000..ee63313 --- /dev/null +++ b/app/components/RegionLabel.vue @@ -0,0 +1,20 @@ + + + diff --git a/app/composables/prefs.ts b/app/composables/prefs.ts index f9f9d8f..457a4c6 100644 --- a/app/composables/prefs.ts +++ b/app/composables/prefs.ts @@ -6,14 +6,6 @@ import { type Region, } from '~~/shared/types.ts' -const FLAGS: Record = { - cn: '🇨🇳', - hk: '🇭🇰', - tw: '🇹🇼', - jp: '🇯🇵', - kr: '🇰🇷', -} - export const HIDDEN_KEY = 'hanji:hidden' const VISIBILITY_VERSION_KEY = 'hanji:columns-v2' const isColumn = (value: string): value is Column => @@ -117,8 +109,9 @@ export function useColumnVisibility() { * set, so they live in localStorage and stay out of the URL. */ export function usePrefs() { - const { t } = useT() - const emojiFlags = useLocalStorage('hanji:emoji-flags', false) + // Keep the original storage key so existing readers retain their choice + // after the visual labels move from platform emoji to local SVG artwork. + const flagLabels = useLocalStorage('hanji:emoji-flags', false) /** * Draw the stacked forms as outlines instead of solid ink. Filled strokes * that agree pile into a single mass; hollow ones stay legible through each @@ -130,17 +123,7 @@ export function usePrefs() { // produces, and localStorage is not available while prerendering. const mounted = ref(false) onMounted(() => (mounted.value = true)) - const flagsOn = computed(() => mounted.value && emojiFlags.value) - - /** Short label for a region, as a flag or as a single character. */ - const regionLabel = (region: Region) => - flagsOn.value ? FLAGS[region] : t(`region.${region}.short`) - - /** - * Flag emoji sit smaller than Han characters at the same font size, so they - * need scaling up to hold the same weight in a row of labels. - */ - const labelClass = computed(() => (flagsOn.value ? 'flag-label' : '')) + const flagsOn = computed(() => mounted.value && flagLabels.value) const outlineOn = computed(() => mounted.value && outline.value) @@ -156,12 +139,10 @@ export function usePrefs() { } = useColumnVisibility() return { - emojiFlags, + flagLabels, flagsOn, outline, outlineOn, - regionLabel, - labelClass, visibleColumns, visibleRegions, regionIndices, diff --git a/app/locales/ja-jp.ts b/app/locales/ja-jp.ts index 2fe0b6c..0485a3d 100644 --- a/app/locales/ja-jp.ts +++ b/app/locales/ja-jp.ts @@ -31,8 +31,8 @@ export const jaJP: typeof zhCN = { options: { title: '表示設定', language: '表示言語', - emoji: '地域を旗で表示', - emojiHint: '「中・日・港・台・韓」を対応する旗の記号に置き換えます。', + flags: '地域を旗で表示', + flagsHint: '「中・日・港・台・韓」を対応する旗の記号に置き換えます。', outline: '重ね表示で輪郭線を使う', outlineHint: '重ねた字形を輪郭線で表示します。画が一つに潰れにくくなり、違いが分かりやすくなります。', diff --git a/app/locales/ko-kr.ts b/app/locales/ko-kr.ts index 2f59049..9943ff7 100644 --- a/app/locales/ko-kr.ts +++ b/app/locales/ko-kr.ts @@ -31,8 +31,8 @@ export const koKR: typeof zhCN = { options: { title: '표시 설정', language: '인터페이스 언어', - emoji: '지역을 국기로 표시', - emojiHint: '‘중·일·홍·대·한’ 표기를 해당 국기 기호로 바꿉니다.', + flags: '지역을 국기로 표시', + flagsHint: '‘중·일·홍·대·한’ 표기를 해당 국기 기호로 바꿉니다.', outline: '겹쳐 보기에서 윤곽선 사용', outlineHint: '겹친 자형을 윤곽선으로 표시해 획이 한 덩어리로 뭉치지 않고 차이가 더 잘 보이게 합니다.', diff --git a/app/locales/zh-cn.ts b/app/locales/zh-cn.ts index f630cdf..9e819f3 100644 --- a/app/locales/zh-cn.ts +++ b/app/locales/zh-cn.ts @@ -29,8 +29,8 @@ export const zhCN = { options: { title: '显示选项', language: '界面语言', - emoji: '用旗帜显示地区', - emojiHint: '把「中日港台韩」换成对应的旗帜符号。', + flags: '用旗帜显示地区', + flagsHint: '把「中日港台韩」换成对应的旗帜符号。', outline: '叠印用空心字', outlineHint: '把叠在一起的字形改成描边,笔画不再糊成一团,分歧处更清楚。', columns: '参与对照的字形', diff --git a/app/locales/zh-hk.ts b/app/locales/zh-hk.ts index 80f6ef0..1cde670 100644 --- a/app/locales/zh-hk.ts +++ b/app/locales/zh-hk.ts @@ -31,8 +31,8 @@ export const zhHK: typeof zhCN = { options: { title: '顯示選項', language: '介面語言', - emoji: '用旗幟顯示地區', - emojiHint: '把「中日港台韓」換成對應的旗幟符號。', + flags: '用旗幟顯示地區', + flagsHint: '把「中日港台韓」換成對應的旗幟符號。', outline: '疊印用空心字', outlineHint: '把疊在一起的字形改成描邊,筆畫不再糊成一團,分歧處更清楚。', columns: '參與對照的字形', diff --git a/app/locales/zh-tw.ts b/app/locales/zh-tw.ts index 47eae06..a82b958 100644 --- a/app/locales/zh-tw.ts +++ b/app/locales/zh-tw.ts @@ -31,8 +31,8 @@ export const zhTW: typeof zhCN = { options: { title: '顯示選項', language: '介面語言', - emoji: '用旗幟顯示地區', - emojiHint: '把「中日港臺韓」換成對應的旗幟符號。', + flags: '用旗幟顯示地區', + flagsHint: '把「中日港臺韓」換成對應的旗幟符號。', outline: '疊印用空心字', outlineHint: '把疊在一起的字形改成描邊,筆畫不再糊成一團,分歧處更清楚。', columns: '參與對照的字形', diff --git a/app/pages/char/[key].vue b/app/pages/char/[key].vue index d70d71f..681b08d 100644 --- a/app/pages/char/[key].vue +++ b/app/pages/char/[key].vue @@ -6,7 +6,7 @@ import { projectSignature, signatureIndexOf, } from '~~/shared/row.ts' -import { REGIONS, type Column } from '~~/shared/types.ts' +import { REGIONS, type Column, type Region } from '~~/shared/types.ts' import { charPath, morphName, @@ -22,7 +22,7 @@ definePageMeta({ layout: 'plain', middleware: 'char-alias' }) const route = useRoute() const { t, list } = useT() -const { regionLabel, labelClass, visibleColumns, visibleRegions } = usePrefs() +const { flagsOn, visibleColumns, visibleRegions } = usePrefs() const key = computed(() => decodeURIComponent(String(route.params.key))) const row = computed(() => rowsByKey.get(key.value)) @@ -217,8 +217,8 @@ const columnsOf = (run: { from: number; span: number }) => * Header label. The kyujitai belongs to Japan, so it carries Japan's mark and * says what it is: 日 旧字体, or the flag and the words when flags are on. */ -const columnMark = (column: Column) => - regionLabel(column === 'old' ? 'jp' : column) +const columnRegion = (column: Column): Region => + column === 'old' ? 'jp' : column const codePointRuns = computed(() => runs((cell) => cell.codePoint)) const strokeRuns = computed(() => runs((cell) => cell.strokes)) const tierRuns = computed(() => runs(tierLabel)) @@ -401,9 +401,10 @@ useSeoMeta({ class="inline-flex items-center gap-1" :title="t(`region.${column}.full`)" > - {{ - columnMark(column) - }} + {{ t('region.old.short') }} @@ -581,12 +582,9 @@ useSeoMeta({ rel="noreferrer" class="inline-flex items-center gap-1.5 border border-rule rounded-md px-3 py-2 text-base text-soft transition-colors duration-150 hover:border-ink/30 hover:text-ink focus-ring" > - {{ regionLabel(link.region) }} + + diff --git a/public/flags/hk.svg b/public/flags/hk.svg new file mode 100644 index 0000000..103d9fc --- /dev/null +++ b/public/flags/hk.svg @@ -0,0 +1 @@ + diff --git a/public/flags/jp.svg b/public/flags/jp.svg new file mode 100644 index 0000000..bab8173 --- /dev/null +++ b/public/flags/jp.svg @@ -0,0 +1 @@ + diff --git a/public/flags/kr.svg b/public/flags/kr.svg new file mode 100644 index 0000000..54b8ceb --- /dev/null +++ b/public/flags/kr.svg @@ -0,0 +1 @@ + diff --git a/public/flags/tw.svg b/public/flags/tw.svg new file mode 100644 index 0000000..eb0c212 --- /dev/null +++ b/public/flags/tw.svg @@ -0,0 +1 @@ + -- 2.51.2