ダークモード
Browse files- effects/base.js +32 -10
- effects/gold.js +1 -1
- effects/multiline-neon.js +1 -1
- index.html +20 -3
- index.js +23 -0
- styles.css +0 -2
effects/base.js
CHANGED
@@ -315,22 +315,44 @@ export class BaseEffect {
|
|
315 |
if (!this.strokeOptions) return;
|
316 |
|
317 |
const { color, width } = this.strokeOptions;
|
|
|
|
|
|
|
|
|
318 |
ctx.strokeStyle = color;
|
319 |
ctx.lineWidth = width;
|
|
|
|
|
320 |
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
}
|
331 |
-
ctx.restore();
|
332 |
}
|
333 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
334 |
}
|
335 |
|
336 |
/**
|
|
|
315 |
if (!this.strokeOptions) return;
|
316 |
|
317 |
const { color, width } = this.strokeOptions;
|
318 |
+
const originalLineWidth = ctx.lineWidth;
|
319 |
+
const originalStrokeStyle = ctx.strokeStyle;
|
320 |
+
|
321 |
+
// 縁取りの設定
|
322 |
ctx.strokeStyle = color;
|
323 |
ctx.lineWidth = width;
|
324 |
+
ctx.lineJoin = 'round'; // 角を丸くする
|
325 |
+
ctx.lineCap = 'round'; // 線の端を丸くする
|
326 |
|
327 |
+
// 外側に広げるため、複数回描画
|
328 |
+
const iterations = 8; // 描画回数
|
329 |
+
const angleStep = (Math.PI * 2) / iterations;
|
330 |
+
|
331 |
+
for (let i = 0; i < iterations; i++) {
|
332 |
+
const angle = i * angleStep;
|
333 |
+
const offsetX = Math.cos(angle) * (width * 0.5);
|
334 |
+
const offsetY = Math.sin(angle) * (width * 0.5);
|
335 |
+
|
336 |
+
for (const lineCoords of this.coordinates) {
|
337 |
+
for (const coord of lineCoords) {
|
338 |
+
ctx.save();
|
339 |
+
if (coord.rotate) {
|
340 |
+
ctx.translate(coord.x + offsetX, coord.y + offsetY);
|
341 |
+
ctx.rotate(Math.PI/2);
|
342 |
+
ctx.strokeText(coord.char, -coord.width/2, 0);
|
343 |
+
} else {
|
344 |
+
ctx.strokeText(coord.char, coord.x + offsetX, coord.y + offsetY);
|
345 |
+
}
|
346 |
+
ctx.restore();
|
347 |
}
|
|
|
348 |
}
|
349 |
}
|
350 |
+
|
351 |
+
// 元の設定を復元
|
352 |
+
ctx.lineWidth = originalLineWidth;
|
353 |
+
ctx.strokeStyle = originalStrokeStyle;
|
354 |
+
ctx.lineJoin = 'miter';
|
355 |
+
ctx.lineCap = 'butt';
|
356 |
}
|
357 |
|
358 |
/**
|
effects/gold.js
CHANGED
@@ -5,7 +5,7 @@ export class GoldEffect extends BaseEffect {
|
|
5 |
super();
|
6 |
this.strokeOptions = {
|
7 |
color: '#b8860b',
|
8 |
-
width:
|
9 |
};
|
10 |
}
|
11 |
|
|
|
5 |
super();
|
6 |
this.strokeOptions = {
|
7 |
color: '#b8860b',
|
8 |
+
width: 2
|
9 |
};
|
10 |
}
|
11 |
|
effects/multiline-neon.js
CHANGED
@@ -10,7 +10,7 @@ export class MultilineNeonEffect extends BaseEffect {
|
|
10 |
};
|
11 |
this.strokeOptions = {
|
12 |
color: '#ffffff',
|
13 |
-
width:
|
14 |
};
|
15 |
}
|
16 |
|
|
|
10 |
};
|
11 |
this.strokeOptions = {
|
12 |
color: '#ffffff',
|
13 |
+
width: 1
|
14 |
};
|
15 |
}
|
16 |
|
index.html
CHANGED
@@ -1,15 +1,25 @@
|
|
1 |
<!DOCTYPE html>
|
2 |
-
<html lang="ja">
|
3 |
|
4 |
<head>
|
5 |
<meta charset="UTF-8">
|
6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7 |
<title>ロゴジェネレーター</title>
|
8 |
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.
|
9 |
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+JP" rel="stylesheet">
|
10 |
<link href="styles.css" rel="stylesheet">
|
11 |
<script type="module" src="effects.js"></script>
|
12 |
<script type="module" src="index.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
</head>
|
14 |
|
15 |
<body>
|
@@ -17,8 +27,15 @@
|
|
17 |
<div class="row justify-content-center">
|
18 |
<div class="col-md-8">
|
19 |
<div class="card">
|
20 |
-
<div class="card-header">
|
21 |
<h2 class="h4 mb-0">ロゴジェネレーター</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</div>
|
23 |
<div class="card-body">
|
24 |
<div class="mb-3">
|
|
|
1 |
<!DOCTYPE html>
|
2 |
+
<html lang="ja" data-bs-theme="light">
|
3 |
|
4 |
<head>
|
5 |
<meta charset="UTF-8">
|
6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7 |
<title>ロゴジェネレーター</title>
|
8 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
9 |
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+JP" rel="stylesheet">
|
10 |
<link href="styles.css" rel="stylesheet">
|
11 |
<script type="module" src="effects.js"></script>
|
12 |
<script type="module" src="index.js"></script>
|
13 |
+
<style>
|
14 |
+
.theme-switch {
|
15 |
+
display: flex;
|
16 |
+
align-items: center;
|
17 |
+
gap: 0.5rem;
|
18 |
+
}
|
19 |
+
.theme-switch .icon {
|
20 |
+
font-size: 1.2rem;
|
21 |
+
}
|
22 |
+
</style>
|
23 |
</head>
|
24 |
|
25 |
<body>
|
|
|
27 |
<div class="row justify-content-center">
|
28 |
<div class="col-md-8">
|
29 |
<div class="card">
|
30 |
+
<div class="card-header d-flex justify-content-between align-items-center">
|
31 |
<h2 class="h4 mb-0">ロゴジェネレーター</h2>
|
32 |
+
<div class="theme-switch">
|
33 |
+
<span class="icon">☀️</span>
|
34 |
+
<div class="form-check form-switch">
|
35 |
+
<input class="form-check-input" type="checkbox" id="themeSwitch">
|
36 |
+
</div>
|
37 |
+
<span class="icon">🌙</span>
|
38 |
+
</div>
|
39 |
</div>
|
40 |
<div class="card-body">
|
41 |
<div class="mb-3">
|
index.js
CHANGED
@@ -636,3 +636,26 @@ document.getElementById('verticalSpacing').addEventListener('input', function (e
|
|
636 |
document.getElementById('verticalSpacingValue').textContent = e.target.value;
|
637 |
// ロゴの再生成処理を呼び出す
|
638 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
636 |
document.getElementById('verticalSpacingValue').textContent = e.target.value;
|
637 |
// ロゴの再生成処理を呼び出す
|
638 |
});
|
639 |
+
|
640 |
+
// ダークモード切り替え機能
|
641 |
+
document.addEventListener('DOMContentLoaded', () => {
|
642 |
+
const themeSwitch = document.getElementById('themeSwitch');
|
643 |
+
|
644 |
+
// 保存された設定を読み込む
|
645 |
+
const savedTheme = localStorage.getItem('theme');
|
646 |
+
if (savedTheme === 'dark') {
|
647 |
+
document.documentElement.setAttribute('data-bs-theme', 'dark');
|
648 |
+
themeSwitch.checked = true;
|
649 |
+
}
|
650 |
+
|
651 |
+
// テーマ切り替えの処理
|
652 |
+
themeSwitch.addEventListener('change', () => {
|
653 |
+
if (themeSwitch.checked) {
|
654 |
+
document.documentElement.setAttribute('data-bs-theme', 'dark');
|
655 |
+
localStorage.setItem('theme', 'dark');
|
656 |
+
} else {
|
657 |
+
document.documentElement.setAttribute('data-bs-theme', 'light');
|
658 |
+
localStorage.setItem('theme', 'light');
|
659 |
+
}
|
660 |
+
});
|
661 |
+
});
|
styles.css
CHANGED
@@ -32,7 +32,6 @@
|
|
32 |
}
|
33 |
|
34 |
.effect-item {
|
35 |
-
background: #f8f9fa;
|
36 |
border: 1px solid #dee2e6;
|
37 |
border-radius: 0.5rem;
|
38 |
padding: 1rem;
|
@@ -48,7 +47,6 @@
|
|
48 |
}
|
49 |
|
50 |
.effect-item.error {
|
51 |
-
background: #fff3f3;
|
52 |
border-color: #ffcdd2;
|
53 |
}
|
54 |
|
|
|
32 |
}
|
33 |
|
34 |
.effect-item {
|
|
|
35 |
border: 1px solid #dee2e6;
|
36 |
border-radius: 0.5rem;
|
37 |
padding: 1rem;
|
|
|
47 |
}
|
48 |
|
49 |
.effect-item.error {
|
|
|
50 |
border-color: #ffcdd2;
|
51 |
}
|
52 |
|