fontのフィルタリング改善
Browse files- index.html +5 -9
- index.js +218 -74
- styles.css +56 -0
index.html
CHANGED
@@ -30,18 +30,14 @@
|
|
30 |
<label for="googleFontInput" class="form-label">フォント</label>
|
31 |
<div class="row g-2 mb-2">
|
32 |
<div class="col">
|
33 |
-
<div class="btn-group w-100" role="group" id="fontTagFilter">
|
34 |
-
|
35 |
-
<label class="btn btn-outline-primary" for="filterAll">すべて表示</label>
|
36 |
-
|
37 |
-
<input type="radio" class="btn-check" name="fontFilter" id="filterJapanese" value="japanese">
|
38 |
-
<label class="btn btn-outline-primary" for="filterJapanese">日本語フォント</label>
|
39 |
-
|
40 |
-
<input type="radio" class="btn-check" name="fontFilter" id="filterKanji" value="kanji">
|
41 |
-
<label class="btn btn-outline-primary" for="filterKanji">漢字対応</label>
|
42 |
</div>
|
43 |
</div>
|
44 |
</div>
|
|
|
|
|
|
|
45 |
<select name="googleFontInput" class="form-select" id="googleFontInput">
|
46 |
</select>
|
47 |
</div>
|
|
|
30 |
<label for="googleFontInput" class="form-label">フォント</label>
|
31 |
<div class="row g-2 mb-2">
|
32 |
<div class="col">
|
33 |
+
<div class="btn-group w-100 flex-wrap gap-1" role="group" id="fontTagFilter">
|
34 |
+
<!-- フィルターボタンはJavaScriptで動的に生成されます -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
</div>
|
36 |
</div>
|
37 |
</div>
|
38 |
+
<div id="noFontsMessage" class="alert alert-danger mb-2" style="display: none;">
|
39 |
+
選択した条件に一致するフォントが見つかりませんでした
|
40 |
+
</div>
|
41 |
<select name="googleFontInput" class="form-select" id="googleFontInput">
|
42 |
</select>
|
43 |
</div>
|
index.js
CHANGED
@@ -1,70 +1,114 @@
|
|
1 |
import { applyEffect, getAvailableEffects } from './effects.js';
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
const fontTags = [
|
|
|
4 |
{ name: "Aoboshi One", tags: ["japanese"] },
|
5 |
-
{ name: "BIZ UDGothic", tags: ["japanese", "kanji"] },
|
6 |
-
{ name: "BIZ UDMincho", tags: ["japanese", "kanji"] },
|
7 |
-
{ name: "BIZ UDPGothic", tags: ["japanese", "kanji"] },
|
8 |
-
{ name: "BIZ UDPMincho", tags: ["japanese", "kanji"] },
|
9 |
-
{ name: "Cherry Bomb One", tags: ["japanese"] },
|
10 |
-
{ name: "Chokokutai", tags: ["japanese"] },
|
11 |
-
{ name: "Darumadrop One", tags: ["japanese"] },
|
12 |
-
{ name: "Dela Gothic One", tags: ["japanese", "kanji"] },
|
13 |
-
{ name: "DotGothic16", tags: ["japanese", "kanji"] },
|
14 |
-
{ name: "Hachi Maru Pop", tags: ["japanese", "kanji"] },
|
15 |
-
{ name: "Hina Mincho", tags: ["japanese", "kanji"] },
|
16 |
-
{ name: "IBM Plex Sans JP", tags: ["japanese", "kanji"] },
|
17 |
-
{ name: "Kaisei Decol", tags: ["japanese", "kanji"] },
|
18 |
-
{ name: "Kaisei HarunoUmi", tags: ["japanese", "kanji"] },
|
19 |
-
{ name: "Kaisei Opti", tags: ["japanese", "kanji"] },
|
20 |
-
{ name: "Kaisei Tokumin", tags: ["japanese", "kanji"] },
|
21 |
-
{ name: "Kiwi Maru", tags: ["japanese", "kanji"] },
|
22 |
-
{ name: "Klee One", tags: ["japanese", "kanji"] },
|
23 |
-
{ name: "Kosugi", tags: ["japanese", "kanji"] },
|
24 |
-
{ name: "Kosugi Maru", tags: ["japanese", "kanji"] },
|
25 |
-
{ name: "M PLUS 1", tags: ["japanese", "kanji"] },
|
26 |
-
{ name: "M PLUS 1 Code", tags: ["japanese", "kanji"] },
|
27 |
-
{ name: "M PLUS 1p", tags: ["japanese", "kanji"] },
|
28 |
-
{ name: "M PLUS 2", tags: ["japanese", "kanji"] },
|
29 |
-
{ name: "M PLUS Rounded 1c", tags: ["japanese", "kanji"] },
|
30 |
-
{ name: "Mochiy Pop One", tags: ["japanese", "kanji"] },
|
31 |
-
{ name: "Mochiy Pop P One", tags: ["japanese", "kanji"] },
|
32 |
-
{ name: "Monomaniac One", tags: ["japanese"] },
|
33 |
-
{ name: "Murecho", tags: ["japanese"] },
|
34 |
-
{ name: "New Tegomin", tags: ["japanese", "kanji"] },
|
35 |
-
{ name: "Noto Sans JP", tags: ["japanese", "kanji"] },
|
36 |
-
{ name: "Noto Serif JP", tags: ["japanese", "kanji"] },
|
37 |
-
{ name: "Palette Mosaic", tags: ["japanese"] },
|
38 |
-
{ name: "Potta One", tags: ["japanese", "kanji"] },
|
39 |
-
{ name: "Rampart One", tags: ["japanese", "kanji"] },
|
40 |
-
{ name: "Reggae One", tags: ["japanese", "kanji"] },
|
41 |
-
{ name: "Rock 3D", tags: ["japanese"] },
|
42 |
-
{ name: "RocknRoll One", tags: ["japanese", "kanji"] },
|
43 |
-
{ name: "Sawarabi Gothic", tags: ["japanese", "kanji"] },
|
44 |
-
{ name: "Sawarabi Mincho", tags: ["japanese", "kanji"] },
|
45 |
-
{ name: "Shippori Antique", tags: ["japanese", "kanji"] },
|
46 |
-
{ name: "Shippori Antique B1", tags: ["japanese", "kanji"] },
|
47 |
-
{ name: "Shippori Mincho", tags: ["japanese", "kanji"] },
|
48 |
-
{ name: "Shippori Mincho B1", tags: ["japanese", "kanji"] },
|
49 |
-
{ name: "Shizuru", tags: ["japanese"] },
|
50 |
-
{ name: "Slackside One", tags: ["japanese"] },
|
51 |
-
{ name: "Stick", tags: ["japanese", "kanji"] },
|
52 |
-
{ name: "Train One", tags: ["japanese", "kanji"] },
|
53 |
-
{ name: "Tsukimi Rounded", tags: ["japanese"] },
|
54 |
-
{ name: "Yomogi", tags: ["japanese", "kanji"] },
|
55 |
-
{ name: "Yuji Boku", tags: ["japanese", "kanji"] },
|
56 |
-
{ name: "Yuji Hentaigana Akari", tags: ["japanese"] },
|
57 |
-
{ name: "Yuji Hentaigana Akebono", tags: ["japanese"] },
|
58 |
-
{ name: "Yuji Mai", tags: ["japanese", "kanji"] },
|
59 |
-
{ name: "Yuji Syuku", tags: ["japanese", "kanji"] },
|
60 |
-
{ name: "Yusei Magic", tags: ["japanese", "kanji"] },
|
61 |
-
{ name: "Zen Antique", tags: ["japanese", "kanji"] },
|
62 |
-
{ name: "Zen Antique Soft", tags: ["japanese", "kanji"] },
|
63 |
-
{ name: "Zen Kaku Gothic Antique", tags: ["japanese", "kanji"] },
|
64 |
-
{ name: "Zen Kaku Gothic New", tags: ["japanese", "kanji"] },
|
65 |
-
{ name: "Zen Kurenaido", tags: ["japanese"] },
|
66 |
-
{ name: "Zen Maru Gothic", tags: ["japanese"] },
|
67 |
-
{ name: "Zen Old Mincho", tags: ["japanese", "kanji"] }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
];
|
69 |
|
70 |
|
@@ -159,20 +203,119 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
159 |
const fontSizeInput = document.getElementById('fontSize');
|
160 |
const verticalTextInput = document.getElementById('verticalText');
|
161 |
const effectGrid = document.querySelector('.effect-grid');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
|
163 |
// フォントオプションの初期化と絞り込み機能の実装
|
164 |
-
function initializeFontOptions(
|
165 |
// 現在選択されているフォントを保持
|
166 |
const currentFont = fontSelect.value;
|
167 |
|
|
|
|
|
|
|
|
|
168 |
// 既存のオプションをクリア
|
169 |
fontSelect.innerHTML = '';
|
170 |
|
171 |
// フィルタリングされたフォントのリストを作成
|
172 |
-
const filteredFonts =
|
173 |
-
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
|
177 |
// フォントオプションを追加
|
178 |
filteredFonts.forEach((font, index) => {
|
@@ -191,17 +334,18 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
191 |
}
|
192 |
|
193 |
// タグフィルターの変更イベントを設定
|
194 |
-
fontTagFilter.
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
await renderAllPresets();
|
199 |
}
|
200 |
-
}
|
201 |
});
|
202 |
|
203 |
// 初期化
|
204 |
-
|
|
|
205 |
await loadGoogleFont(fontSelect.value);
|
206 |
|
207 |
// 縦書きモードの状態をグリッドに反映
|
|
|
1 |
import { applyEffect, getAvailableEffects } from './effects.js';
|
2 |
|
3 |
+
const tagDisplayNames = {
|
4 |
+
japanese: "日本語",
|
5 |
+
english: "英語",
|
6 |
+
kanji: "漢字対応",
|
7 |
+
business: "ビジネス",
|
8 |
+
fancy: "装飾的",
|
9 |
+
playful: "遊び心",
|
10 |
+
display: "ディスプレイ",
|
11 |
+
handwritten: "手書き",
|
12 |
+
retro: "レトロ",
|
13 |
+
calm: "落ち着いた",
|
14 |
+
cute: "かわいい",
|
15 |
+
script: "筆記体",
|
16 |
+
bold: "太字",
|
17 |
+
horror: "ホラー",
|
18 |
+
comic: "コミック"
|
19 |
+
};
|
20 |
+
|
21 |
const fontTags = [
|
22 |
+
// 日本語フォント
|
23 |
{ name: "Aoboshi One", tags: ["japanese"] },
|
24 |
+
{ name: "BIZ UDGothic", tags: ["japanese", "kanji", "business"] },
|
25 |
+
{ name: "BIZ UDMincho", tags: ["japanese", "kanji", "business"] },
|
26 |
+
{ name: "BIZ UDPGothic", tags: ["japanese", "kanji", "business"] },
|
27 |
+
{ name: "BIZ UDPMincho", tags: ["japanese", "kanji", "business"] },
|
28 |
+
{ name: "Cherry Bomb One", tags: ["japanese", "cute"] },
|
29 |
+
{ name: "Chokokutai", tags: ["japanese", "fancy"] },
|
30 |
+
{ name: "Darumadrop One", tags: ["japanese", "playful"] },
|
31 |
+
{ name: "Dela Gothic One", tags: ["japanese", "kanji", "display"] },
|
32 |
+
{ name: "DotGothic16", tags: ["japanese", "kanji", "retro"] },
|
33 |
+
{ name: "Hachi Maru Pop", tags: ["japanese", "kanji", "cute"] },
|
34 |
+
{ name: "Hina Mincho", tags: ["japanese", "kanji", "fancy"] },
|
35 |
+
{ name: "IBM Plex Sans JP", tags: ["japanese", "kanji", "business"] },
|
36 |
+
{ name: "Kaisei Decol", tags: ["japanese", "kanji", "fancy"] },
|
37 |
+
{ name: "Kaisei HarunoUmi", tags: ["japanese", "kanji", "fancy"] },
|
38 |
+
{ name: "Kaisei Opti", tags: ["japanese", "kanji", "business"] },
|
39 |
+
{ name: "Kaisei Tokumin", tags: ["japanese", "kanji", "business"] },
|
40 |
+
{ name: "Kiwi Maru", tags: ["japanese", "kanji", "cute"] },
|
41 |
+
{ name: "Klee One", tags: ["japanese", "kanji", "handwritten"] },
|
42 |
+
{ name: "Kosugi", tags: ["japanese", "kanji", "business"] },
|
43 |
+
{ name: "Kosugi Maru", tags: ["japanese", "kanji", "calm"] },
|
44 |
+
{ name: "M PLUS 1", tags: ["japanese", "kanji", "business"] },
|
45 |
+
{ name: "M PLUS 1 Code", tags: ["japanese", "kanji", "display"] },
|
46 |
+
{ name: "M PLUS 1p", tags: ["japanese", "kanji", "business"] },
|
47 |
+
{ name: "M PLUS 2", tags: ["japanese", "kanji", "business"] },
|
48 |
+
{ name: "M PLUS Rounded 1c", tags: ["japanese", "kanji", "calm"] },
|
49 |
+
{ name: "Mochiy Pop One", tags: ["japanese", "kanji", "playful"] },
|
50 |
+
{ name: "Mochiy Pop P One", tags: ["japanese", "kanji", "playful"] },
|
51 |
+
{ name: "Monomaniac One", tags: ["japanese", "display"] },
|
52 |
+
{ name: "Murecho", tags: ["japanese", "business"] },
|
53 |
+
{ name: "New Tegomin", tags: ["japanese", "kanji", "fancy"] },
|
54 |
+
{ name: "Noto Sans JP", tags: ["japanese", "kanji", "business"] },
|
55 |
+
{ name: "Noto Serif JP", tags: ["japanese", "kanji", "business"] },
|
56 |
+
{ name: "Palette Mosaic", tags: ["japanese", "display"] },
|
57 |
+
{ name: "Potta One", tags: ["japanese", "kanji", "playful"] },
|
58 |
+
{ name: "Rampart One", tags: ["japanese", "kanji", "display"] },
|
59 |
+
{ name: "Reggae One", tags: ["japanese", "kanji", "display"] },
|
60 |
+
{ name: "Rock 3D", tags: ["japanese", "display"] },
|
61 |
+
{ name: "RocknRoll One", tags: ["japanese", "kanji", "playful"] },
|
62 |
+
{ name: "Sawarabi Gothic", tags: ["japanese", "kanji", "business"] },
|
63 |
+
{ name: "Sawarabi Mincho", tags: ["japanese", "kanji", "business"] },
|
64 |
+
{ name: "Shippori Antique", tags: ["japanese", "kanji", "retro"] },
|
65 |
+
{ name: "Shippori Antique B1", tags: ["japanese", "kanji", "retro"] },
|
66 |
+
{ name: "Shippori Mincho", tags: ["japanese", "kanji", "business"] },
|
67 |
+
{ name: "Shippori Mincho B1", tags: ["japanese", "kanji", "business"] },
|
68 |
+
{ name: "Shizuru", tags: ["japanese", "display"] },
|
69 |
+
{ name: "Slackside One", tags: ["japanese", "handwritten"] },
|
70 |
+
{ name: "Stick", tags: ["japanese", "kanji", "display"] },
|
71 |
+
{ name: "Train One", tags: ["japanese", "kanji", "display"] },
|
72 |
+
{ name: "Tsukimi Rounded", tags: ["japanese", "calm"] },
|
73 |
+
{ name: "Yomogi", tags: ["japanese", "kanji", "handwritten"] },
|
74 |
+
{ name: "Yuji Boku", tags: ["japanese", "kanji", "fancy"] },
|
75 |
+
{ name: "Yuji Hentaigana Akari", tags: ["japanese", "fancy"] },
|
76 |
+
{ name: "Yuji Hentaigana Akebono", tags: ["japanese", "fancy"] },
|
77 |
+
{ name: "Yuji Mai", tags: ["japanese", "kanji", "fancy"] },
|
78 |
+
{ name: "Yuji Syuku", tags: ["japanese", "kanji", "fancy"] },
|
79 |
+
{ name: "Yusei Magic", tags: ["japanese", "kanji", "playful"] },
|
80 |
+
{ name: "Zen Antique", tags: ["japanese", "kanji", "retro"] },
|
81 |
+
{ name: "Zen Antique Soft", tags: ["japanese", "kanji", "retro"] },
|
82 |
+
{ name: "Zen Kaku Gothic Antique", tags: ["japanese", "kanji", "business"] },
|
83 |
+
{ name: "Zen Kaku Gothic New", tags: ["japanese", "kanji", "business"] },
|
84 |
+
{ name: "Zen Kurenaido", tags: ["japanese", "calm"] },
|
85 |
+
{ name: "Zen Maru Gothic", tags: ["japanese", "calm"] },
|
86 |
+
{ name: "Zen Old Mincho", tags: ["japanese", "kanji", "retro"] },
|
87 |
+
|
88 |
+
// 英語フォント - ビジネス/フォーマル
|
89 |
+
{ name: "Montserrat", tags: ["english", "business"] },
|
90 |
+
{ name: "Playfair Display", tags: ["english", "business", "fancy"] },
|
91 |
+
{ name: "Roboto", tags: ["english", "business"] },
|
92 |
+
{ name: "Lato", tags: ["english", "business"] },
|
93 |
+
|
94 |
+
// デコラティブ/ファンシー
|
95 |
+
{ name: "Pacifico", tags: ["english", "fancy", "script"] },
|
96 |
+
{ name: "Great Vibes", tags: ["english", "fancy", "script"] },
|
97 |
+
{ name: "Lobster", tags: ["english", "fancy"] },
|
98 |
+
{ name: "Dancing Script", tags: ["english", "fancy", "script"] },
|
99 |
+
{ name: "Satisfy", tags: ["english", "fancy", "script"] },
|
100 |
+
|
101 |
+
// ディスプレイ/特殊
|
102 |
+
{ name: "Righteous", tags: ["english", "display"] },
|
103 |
+
{ name: "Permanent Marker", tags: ["english", "display", "handwritten"] },
|
104 |
+
{ name: "Press Start 2P", tags: ["english", "display", "retro"] },
|
105 |
+
{ name: "Fredoka One", tags: ["english", "display", "playful"] },
|
106 |
+
{ name: "Creepster", tags: ["english", "display", "horror"] },
|
107 |
+
{ name: "Bangers", tags: ["english", "display", "comic"] },
|
108 |
+
{ name: "Rubik Mono One", tags: ["english", "display", "bold"] },
|
109 |
+
{ name: "Bungee", tags: ["english", "display", "bold"] },
|
110 |
+
{ name: "Bungee Shade", tags: ["english", "display", "fancy"] },
|
111 |
+
{ name: "Monoton", tags: ["english", "display", "retro"] }
|
112 |
];
|
113 |
|
114 |
|
|
|
203 |
const fontSizeInput = document.getElementById('fontSize');
|
204 |
const verticalTextInput = document.getElementById('verticalText');
|
205 |
const effectGrid = document.querySelector('.effect-grid');
|
206 |
+
const noFontsMessage = document.getElementById('noFontsMessage');
|
207 |
+
|
208 |
+
// 利用可能なタグを収集し、使用頻度をカウント
|
209 |
+
function getTagsWithCount() {
|
210 |
+
const tagCount = new Map();
|
211 |
+
fontTags.forEach(font => {
|
212 |
+
font.tags.forEach(tag => {
|
213 |
+
tagCount.set(tag, (tagCount.get(tag) || 0) + 1);
|
214 |
+
});
|
215 |
+
});
|
216 |
+
return tagCount;
|
217 |
+
}
|
218 |
+
|
219 |
+
// 言語関連のタグかどうかを判定
|
220 |
+
function isLanguageTag(tag) {
|
221 |
+
return ['japanese', 'english', 'kanji'].includes(tag);
|
222 |
+
}
|
223 |
+
|
224 |
+
// フィルターボタンを動的に生成
|
225 |
+
function createFilterButtons() {
|
226 |
+
const tagCount = getTagsWithCount();
|
227 |
+
fontTagFilter.innerHTML = '';
|
228 |
+
|
229 |
+
// タグを言語関連とその他に分類し、個数でソート
|
230 |
+
const languageTags = [...tagCount.entries()]
|
231 |
+
.filter(([tag]) => isLanguageTag(tag))
|
232 |
+
.sort((a, b) => b[1] - a[1]);
|
233 |
+
|
234 |
+
const otherTags = [...tagCount.entries()]
|
235 |
+
.filter(([tag]) => !isLanguageTag(tag))
|
236 |
+
.sort((a, b) => b[1] - a[1]);
|
237 |
+
|
238 |
+
// 言語関連のタグを追加
|
239 |
+
if (languageTags.length > 0) {
|
240 |
+
const langGroup = document.createElement('div');
|
241 |
+
langGroup.className = 'filter-group mb-2';
|
242 |
+
langGroup.innerHTML = '<div class="filter-group-label mb-1">言語</div>';
|
243 |
+
|
244 |
+
const langButtonGroup = document.createElement('div');
|
245 |
+
langButtonGroup.className = 'btn-group-wrapper';
|
246 |
+
|
247 |
+
languageTags.forEach(([tag, count]) => {
|
248 |
+
const displayName = tagDisplayNames[tag] || tag;
|
249 |
+
const button = document.createElement('div');
|
250 |
+
button.className = 'btn-check-wrapper';
|
251 |
+
button.innerHTML = `
|
252 |
+
<input type="checkbox" class="btn-check" name="fontFilter" id="filter${tag}" value="${tag}">
|
253 |
+
<label class="btn btn-outline-primary" for="filter${tag}">
|
254 |
+
${displayName} <span class="tag-count">(${count})</span>
|
255 |
+
</label>
|
256 |
+
`;
|
257 |
+
langButtonGroup.appendChild(button);
|
258 |
+
});
|
259 |
+
|
260 |
+
langGroup.appendChild(langButtonGroup);
|
261 |
+
fontTagFilter.appendChild(langGroup);
|
262 |
+
}
|
263 |
+
|
264 |
+
// その他のタグを追加
|
265 |
+
if (otherTags.length > 0) {
|
266 |
+
const otherGroup = document.createElement('div');
|
267 |
+
otherGroup.className = 'filter-group';
|
268 |
+
otherGroup.innerHTML = '<div class="filter-group-label mb-1">スタイル</div>';
|
269 |
+
|
270 |
+
const otherButtonGroup = document.createElement('div');
|
271 |
+
otherButtonGroup.className = 'btn-group-wrapper';
|
272 |
+
|
273 |
+
otherTags.forEach(([tag, count]) => {
|
274 |
+
const displayName = tagDisplayNames[tag] || tag;
|
275 |
+
const button = document.createElement('div');
|
276 |
+
button.className = 'btn-check-wrapper';
|
277 |
+
button.innerHTML = `
|
278 |
+
<input type="checkbox" class="btn-check" name="fontFilter" id="filter${tag}" value="${tag}">
|
279 |
+
<label class="btn btn-outline-primary" for="filter${tag}">
|
280 |
+
${displayName} <span class="tag-count">(${count})</span>
|
281 |
+
</label>
|
282 |
+
`;
|
283 |
+
otherButtonGroup.appendChild(button);
|
284 |
+
});
|
285 |
+
|
286 |
+
otherGroup.appendChild(otherButtonGroup);
|
287 |
+
fontTagFilter.appendChild(otherGroup);
|
288 |
+
}
|
289 |
+
}
|
290 |
|
291 |
// フォントオプションの初期化と絞り込み機能の実装
|
292 |
+
function initializeFontOptions() {
|
293 |
// 現在選択されているフォントを保持
|
294 |
const currentFont = fontSelect.value;
|
295 |
|
296 |
+
// 選択されているフィルターを取得
|
297 |
+
const selectedFilters = Array.from(fontTagFilter.querySelectorAll('input[type="checkbox"]:checked'))
|
298 |
+
.map(checkbox => checkbox.value);
|
299 |
+
|
300 |
// 既存のオプションをクリア
|
301 |
fontSelect.innerHTML = '';
|
302 |
|
303 |
// フィルタリングされたフォントのリストを作成
|
304 |
+
const filteredFonts = selectedFilters.length === 0
|
305 |
+
? fontTags
|
306 |
+
: fontTags.filter(font =>
|
307 |
+
selectedFilters.every(filter => font.tags.includes(filter))
|
308 |
+
);
|
309 |
+
|
310 |
+
// フォルター結果が0件の場合
|
311 |
+
if (filteredFonts.length === 0) {
|
312 |
+
noFontsMessage.style.display = 'block';
|
313 |
+
fontSelect.disabled = true;
|
314 |
+
return Promise.resolve(); // フォントの読み込みは不要
|
315 |
+
} else {
|
316 |
+
noFontsMessage.style.display = 'none';
|
317 |
+
fontSelect.disabled = false;
|
318 |
+
}
|
319 |
|
320 |
// フォントオプションを追加
|
321 |
filteredFonts.forEach((font, index) => {
|
|
|
334 |
}
|
335 |
|
336 |
// タグフィルターの変更イベントを設定
|
337 |
+
fontTagFilter.addEventListener('change', async (e) => {
|
338 |
+
if (e.target.type === 'checkbox') {
|
339 |
+
await initializeFontOptions();
|
340 |
+
if (!fontSelect.disabled) { // フォントが選択可能な場合のみプレビューを更新
|
341 |
await renderAllPresets();
|
342 |
}
|
343 |
+
}
|
344 |
});
|
345 |
|
346 |
// 初期化
|
347 |
+
createFilterButtons();
|
348 |
+
await initializeFontOptions();
|
349 |
await loadGoogleFont(fontSelect.value);
|
350 |
|
351 |
// 縦書きモードの状態をグリッドに反映
|
styles.css
CHANGED
@@ -114,4 +114,60 @@
|
|
114 |
0% { transform: translateY(0) translateX(0); }
|
115 |
50% { transform: translateY(-10px) translateX(5px); }
|
116 |
100% { transform: translateY(0) translateX(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
}
|
|
|
114 |
0% { transform: translateY(0) translateX(0); }
|
115 |
50% { transform: translateY(-10px) translateX(5px); }
|
116 |
100% { transform: translateY(0) translateX(0); }
|
117 |
+
}
|
118 |
+
|
119 |
+
.btn-check-wrapper {
|
120 |
+
display: inline-block;
|
121 |
+
margin: 2px;
|
122 |
+
}
|
123 |
+
|
124 |
+
.btn-check-wrapper .btn {
|
125 |
+
margin: 0;
|
126 |
+
white-space: nowrap;
|
127 |
+
}
|
128 |
+
|
129 |
+
#fontTagFilter {
|
130 |
+
display: flex;
|
131 |
+
flex-wrap: wrap;
|
132 |
+
gap: 0.25rem;
|
133 |
+
}
|
134 |
+
|
135 |
+
#fontTagFilter .btn {
|
136 |
+
border-radius: 0.25rem;
|
137 |
+
font-size: 0.875rem;
|
138 |
+
padding: 0.25rem 0.5rem;
|
139 |
+
}
|
140 |
+
|
141 |
+
/* チェックされた状態のスタイル */
|
142 |
+
.btn-check:checked + .btn-outline-primary {
|
143 |
+
background-color: #0d6efd;
|
144 |
+
color: white;
|
145 |
+
}
|
146 |
+
|
147 |
+
.filter-group {
|
148 |
+
margin-bottom: 1rem;
|
149 |
+
}
|
150 |
+
|
151 |
+
.filter-group-label {
|
152 |
+
font-size: 0.875rem;
|
153 |
+
font-weight: 600;
|
154 |
+
color: #6c757d;
|
155 |
+
margin-bottom: 0.5rem;
|
156 |
+
}
|
157 |
+
|
158 |
+
.btn-group-wrapper {
|
159 |
+
display: flex;
|
160 |
+
flex-wrap: wrap;
|
161 |
+
gap: 0.25rem;
|
162 |
+
}
|
163 |
+
|
164 |
+
.tag-count {
|
165 |
+
font-size: 0.75rem;
|
166 |
+
opacity: 0.8;
|
167 |
+
}
|
168 |
+
|
169 |
+
/* ボタンのホバー時もタグカウントの視認性を保持 */
|
170 |
+
.btn-check:checked + .btn-outline-primary .tag-count,
|
171 |
+
.btn-outline-primary:hover .tag-count {
|
172 |
+
opacity: 1;
|
173 |
}
|