@jjlmoya/utils-chrono 1.20.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +2 -0
- package/src/entries.ts +4 -1
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/watch-crystal-material-comparison/bibliography.astro +16 -0
- package/src/tool/watch-crystal-material-comparison/bibliography.ts +16 -0
- package/src/tool/watch-crystal-material-comparison/client.ts +150 -0
- package/src/tool/watch-crystal-material-comparison/component.astro +15 -0
- package/src/tool/watch-crystal-material-comparison/components/CrystalPanel.astro +20 -0
- package/src/tool/watch-crystal-material-comparison/entry.ts +43 -0
- package/src/tool/watch-crystal-material-comparison/helpers.ts +49 -0
- package/src/tool/watch-crystal-material-comparison/i18n/de.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/en.ts +90 -0
- package/src/tool/watch-crystal-material-comparison/i18n/es.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/fr.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/id.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/it.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/ja.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/ko.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/nl.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/pl.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/pt.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/ru.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/sv.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/tr.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/i18n/zh.ts +35 -0
- package/src/tool/watch-crystal-material-comparison/index.ts +11 -0
- package/src/tool/watch-crystal-material-comparison/logic.ts +55 -0
- package/src/tool/watch-crystal-material-comparison/seo.astro +16 -0
- package/src/tool/watch-crystal-material-comparison/watch-crystal-material-comparison.css +625 -0
- package/src/tools.ts +2 -0
package/package.json
CHANGED
package/src/category/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { gmtWorldTimer } from '../tool/gmt-world-timer/entry';
|
|
|
22
22
|
import { quartzBatteryHealth } from '../tool/quartz-battery-health/entry';
|
|
23
23
|
import { mainspringFinder } from '../tool/mainspring-finder/entry';
|
|
24
24
|
import { altitudeWatchAccuracyEstimator } from '../tool/altitude-watch-accuracy-estimator/entry';
|
|
25
|
+
import { watchCrystalMaterialComparison } from '../tool/watch-crystal-material-comparison/entry';
|
|
25
26
|
|
|
26
27
|
export const chronoCategory: ChronoCategoryEntry = {
|
|
27
28
|
icon: 'mdi:clock-outline',
|
|
@@ -49,6 +50,7 @@ export const chronoCategory: ChronoCategoryEntry = {
|
|
|
49
50
|
quartzBatteryHealth,
|
|
50
51
|
mainspringFinder,
|
|
51
52
|
altitudeWatchAccuracyEstimator,
|
|
53
|
+
watchCrystalMaterialComparison,
|
|
52
54
|
],
|
|
53
55
|
i18n: {
|
|
54
56
|
de: () => import('./i18n/de').then((m) => m.content),
|
package/src/entries.ts
CHANGED
|
@@ -46,6 +46,8 @@ export { mainspringFinder } from './tool/mainspring-finder/entry';
|
|
|
46
46
|
export type { MainspringFinderUI, MainspringFinderLocaleContent } from './tool/mainspring-finder/entry';
|
|
47
47
|
export { altitudeWatchAccuracyEstimator } from './tool/altitude-watch-accuracy-estimator/entry';
|
|
48
48
|
export type { AltitudeWatchAccuracyEstimatorUI, AltitudeWatchAccuracyEstimatorLocaleContent } from './tool/altitude-watch-accuracy-estimator/entry';
|
|
49
|
+
export { watchCrystalMaterialComparison } from './tool/watch-crystal-material-comparison/entry';
|
|
50
|
+
export type { WatchCrystalMaterialComparisonUI, WatchCrystalMaterialComparisonLocaleContent } from './tool/watch-crystal-material-comparison/entry';
|
|
49
51
|
export { chronoCategory } from './category';
|
|
50
52
|
|
|
51
53
|
import { watchAccuracyTracker } from './tool/watch-accuracy-tracker/entry';
|
|
@@ -72,6 +74,7 @@ import { gmtWorldTimer } from './tool/gmt-world-timer/entry';
|
|
|
72
74
|
import { quartzBatteryHealth } from './tool/quartz-battery-health/entry';
|
|
73
75
|
import { mainspringFinder } from './tool/mainspring-finder/entry';
|
|
74
76
|
import { altitudeWatchAccuracyEstimator } from './tool/altitude-watch-accuracy-estimator/entry';
|
|
77
|
+
import { watchCrystalMaterialComparison } from './tool/watch-crystal-material-comparison/entry';
|
|
75
78
|
|
|
76
|
-
export const ALL_ENTRIES = [watchAccuracyTracker, wristPresenceCalculator, demagnetizingTimer, watchSavingsPlanner, crownReferenceGuide, powerReserveEstimator, beatRateConverter, waterResistanceConverter, strapTaperCalculator, watchSizeComparator, lumeColorSimulator, moonPhaseVisualizer, tachymeterCalculator, serviceIntervalTracker, strapLengthCalculator, telemeterCalculator, siderealTimeTracker, gearTrainExplorer, perpetualCalendar, tourbillonVisualizer, gmtWorldTimer, quartzBatteryHealth, mainspringFinder, altitudeWatchAccuracyEstimator];
|
|
79
|
+
export const ALL_ENTRIES = [watchAccuracyTracker, wristPresenceCalculator, demagnetizingTimer, watchSavingsPlanner, crownReferenceGuide, powerReserveEstimator, beatRateConverter, waterResistanceConverter, strapTaperCalculator, watchSizeComparator, lumeColorSimulator, moonPhaseVisualizer, tachymeterCalculator, serviceIntervalTracker, strapLengthCalculator, telemeterCalculator, siderealTimeTracker, gearTrainExplorer, perpetualCalendar, tourbillonVisualizer, gmtWorldTimer, quartzBatteryHealth, mainspringFinder, altitudeWatchAccuracyEstimator, watchCrystalMaterialComparison];
|
|
77
80
|
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export { strapLengthCalculator, STRAP_LENGTH_CALCULATOR_TOOL } from './tool/stra
|
|
|
18
18
|
export { quartzBatteryHealth, QUARTZ_BATTERY_HEALTH_TOOL } from './tool/quartz-battery-health';
|
|
19
19
|
export { mainspringFinder, MAINSPRING_FINDER_TOOL } from './tool/mainspring-finder';
|
|
20
20
|
export { altitudeWatchAccuracyEstimator, ALTITUDE_WATCH_ACCURACY_ESTIMATOR_TOOL } from './tool/altitude-watch-accuracy-estimator';
|
|
21
|
+
export { watchCrystalMaterialComparison, WATCH_CRYSTAL_MATERIAL_COMPARISON_TOOL } from './tool/watch-crystal-material-comparison';
|
|
21
22
|
|
|
22
23
|
export type {
|
|
23
24
|
KnownLocale,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { watchCrystalMaterialComparison } from './index';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
locale?: KnownLocale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { locale = 'en' } = Astro.props as Props;
|
|
11
|
+
const loader = watchCrystalMaterialComparison.i18n[locale] || watchCrystalMaterialComparison.i18n.en;
|
|
12
|
+
const content = await loader?.();
|
|
13
|
+
if (!content) return null;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
{content && <SharedBibliography links={content.bibliography} />}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BibliographyEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const bibliography: BibliographyEntry[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'Technical Perspective | A Comprehensive Guide to Watch Crystals - Plexiglass, Mineral, Hesalite, Sapphire Crystal - History, Pros and Cons',
|
|
6
|
+
url: 'https://monochrome-watches.com/technical-perspective-comprehensive-guide-to-watch-crystals-plexiglass-mineral-hesalite-sapphire-crystal-history-pros-and-cons/',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'Mohs Scale of Mineral Hardness',
|
|
10
|
+
url: 'https://en.wikipedia.org/wiki/Mohs_scale',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: 'Sapphire Crystal in Watches',
|
|
14
|
+
url: 'https://www.longines.com/en-se/universe/blog/sapphire',
|
|
15
|
+
}
|
|
16
|
+
];
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { CRYSTAL_TYPES, type CrystalData } from './logic';
|
|
2
|
+
|
|
3
|
+
const STATS = [
|
|
4
|
+
{ key: 'hardness', label: 'HARD' },
|
|
5
|
+
{ key: 'clarity', label: 'CLAR' },
|
|
6
|
+
{ key: 'impactResistance', label: 'IMP' },
|
|
7
|
+
{ key: 'scratchResistance', label: 'SCR' },
|
|
8
|
+
{ key: 'durability', label: 'DUR' },
|
|
9
|
+
] as const;
|
|
10
|
+
|
|
11
|
+
type StatKeys = typeof STATS[number]['key'];
|
|
12
|
+
|
|
13
|
+
const listEl = document.getElementById('crystal-list')!;
|
|
14
|
+
const cardWrap = document.getElementById('crystal-card-wrap')!;
|
|
15
|
+
const fightEl = document.getElementById('crystal-fight')!;
|
|
16
|
+
const dragHint = document.getElementById('crystal-drag-hint')!;
|
|
17
|
+
|
|
18
|
+
let selectedId: string = 'sapphire';
|
|
19
|
+
let fightId: string | null = null;
|
|
20
|
+
let draggedId: string | null = null;
|
|
21
|
+
let hasDragged = false;
|
|
22
|
+
|
|
23
|
+
function priceGems(level: number): string {
|
|
24
|
+
let h = '';
|
|
25
|
+
for (let i = 0; i < 3; i++) {
|
|
26
|
+
h += '<span class="price-gem' + (i < level ? ' filled' : ' empty') + '"></span>';
|
|
27
|
+
}
|
|
28
|
+
return h;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createSparkles(): string {
|
|
32
|
+
let h = '';
|
|
33
|
+
for (let i = 0; i < 12; i++) {
|
|
34
|
+
const x = 5 + Math.random() * 90;
|
|
35
|
+
const y = 5 + Math.random() * 90;
|
|
36
|
+
h += '<div class="card-sparkle" style="left:' + x + '%;top:' + y + '%;animation-delay:' + (Math.random() * 3) + 's;animation-duration:' + (2 + Math.random() * 3) + 's"></div>';
|
|
37
|
+
}
|
|
38
|
+
return h;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function renderCard(crystal: CrystalData): string {
|
|
42
|
+
let h = '<div class="crystal-card-big" style="background:' + crystal.colorBg + '">';
|
|
43
|
+
h += '<div class="card-orb" style="background:' + crystal.color + '"></div>';
|
|
44
|
+
h += '<div class="card-gold-accent"></div><div class="card-pattern"></div>';
|
|
45
|
+
h += '<div class="card-sparkles">' + createSparkles() + '</div>';
|
|
46
|
+
h += '<div class="card-header">';
|
|
47
|
+
h += '<div class="card-ovr-wrap"><div class="card-ovr-ring"></div><div class="card-ovr" style="background:' + crystal.color + '"><span class="card-ovr-num">' + crystal.overall + '</span><span class="card-ovr-label">OVR</span></div></div>';
|
|
48
|
+
h += '<div class="card-title"><span class="card-name">' + crystal.name + '</span><span class="card-name-sub">Watch Crystal</span></div>';
|
|
49
|
+
h += '<div class="card-price-gems">' + priceGems(crystal.priceLevel) + '</div></div>';
|
|
50
|
+
h += '<div class="card-stats">';
|
|
51
|
+
for (let i = 0; i < STATS.length; i++) {
|
|
52
|
+
const val = crystal[STATS[i].key as StatKeys] as number;
|
|
53
|
+
h += '<div class="card-stat" style="animation-delay:' + (i * 0.07) + 's">';
|
|
54
|
+
h += '<span class="card-stat-label">' + STATS[i].label + '</span>';
|
|
55
|
+
h += '<div class="card-stat-bar"><div class="card-stat-bar-glow"></div><div class="card-stat-fill" style="width:' + val + '%;background:' + crystal.color + '"></div></div>';
|
|
56
|
+
h += '<span class="card-stat-val">' + val + '</span></div>';
|
|
57
|
+
}
|
|
58
|
+
h += '</div></div>';
|
|
59
|
+
return h;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function updateCard(crystal: CrystalData) {
|
|
63
|
+
const existing = cardWrap.querySelector('.crystal-card-big');
|
|
64
|
+
if (existing) {
|
|
65
|
+
existing.classList.add('card-leaving');
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
cardWrap.innerHTML = renderCard(crystal);
|
|
68
|
+
const el = cardWrap.querySelector('.crystal-card-big');
|
|
69
|
+
if (el) el.classList.add('card-entering');
|
|
70
|
+
}, 200);
|
|
71
|
+
} else {
|
|
72
|
+
cardWrap.innerHTML = renderCard(crystal);
|
|
73
|
+
const el = cardWrap.querySelector('.crystal-card-big');
|
|
74
|
+
if (el) el.classList.add('card-entering');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function renderList() {
|
|
79
|
+
let h = '';
|
|
80
|
+
for (const c of CRYSTAL_TYPES) {
|
|
81
|
+
const active = c.id === selectedId ? ' active' : '';
|
|
82
|
+
h += '<div class="crystal-list-item' + active + '" data-id="' + c.id + '" draggable="true">';
|
|
83
|
+
h += '<div class="list-grip"><span></span><span></span><span></span></div>';
|
|
84
|
+
h += '<div class="list-ovr" style="background:' + c.color + '">' + c.overall + '</div>';
|
|
85
|
+
h += '<div class="list-info"><span class="list-name">' + c.name + '</span><span class="list-hint">Drag to compare</span></div></div>';
|
|
86
|
+
}
|
|
87
|
+
listEl.innerHTML = h;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function renderFight() {
|
|
91
|
+
if (!fightId) { fightEl.innerHTML = ''; return; }
|
|
92
|
+
const f1 = CRYSTAL_TYPES.find(c => c.id === selectedId) || CRYSTAL_TYPES[0];
|
|
93
|
+
const f2 = CRYSTAL_TYPES.find(c => c.id === fightId) || CRYSTAL_TYPES[0];
|
|
94
|
+
let h = '<div class="crystal-fight"><div class="crystal-fight-grid">';
|
|
95
|
+
h += renderCard(f1) + '<div class="crystal-fight-vs">VS</div>' + renderCard(f2);
|
|
96
|
+
h += '</div><button class="crystal-fight-close" id="fight-close">Close Comparison</button></div>';
|
|
97
|
+
fightEl.innerHTML = h;
|
|
98
|
+
document.getElementById('fight-close')?.addEventListener('click', () => {
|
|
99
|
+
fightId = null;
|
|
100
|
+
render();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function handleDrop(e: Event, itemId: string) {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
const target = e.currentTarget as HTMLElement;
|
|
107
|
+
target.classList.remove('drag-over');
|
|
108
|
+
const dropId = (e as DragEvent).dataTransfer?.getData('text/plain');
|
|
109
|
+
if (dropId && dropId !== itemId) {
|
|
110
|
+
selectedId = dropId;
|
|
111
|
+
fightId = itemId;
|
|
112
|
+
render();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function bindItem(item: Element) {
|
|
117
|
+
const id = (item as HTMLElement).dataset.id || '';
|
|
118
|
+
item.addEventListener('click', () => {
|
|
119
|
+
if (fightId) fightId = null;
|
|
120
|
+
selectedId = id;
|
|
121
|
+
render();
|
|
122
|
+
});
|
|
123
|
+
item.addEventListener('dragstart', (e: Event) => {
|
|
124
|
+
(e as DragEvent).dataTransfer?.setData('text/plain', id);
|
|
125
|
+
draggedId = id;
|
|
126
|
+
hasDragged = true;
|
|
127
|
+
item.classList.add('dragging');
|
|
128
|
+
});
|
|
129
|
+
item.addEventListener('dragend', () => {
|
|
130
|
+
item.classList.remove('dragging');
|
|
131
|
+
draggedId = null;
|
|
132
|
+
});
|
|
133
|
+
item.addEventListener('dragover', (e: Event) => {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
if (id !== draggedId) item.classList.add('drag-over');
|
|
136
|
+
});
|
|
137
|
+
item.addEventListener('dragleave', () => { item.classList.remove('drag-over'); });
|
|
138
|
+
item.addEventListener('drop', (e: Event) => handleDrop(e, id));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function render() {
|
|
142
|
+
renderList();
|
|
143
|
+
const mainCrystal = CRYSTAL_TYPES.find(c => c.id === selectedId) || CRYSTAL_TYPES[0];
|
|
144
|
+
updateCard(mainCrystal);
|
|
145
|
+
renderFight();
|
|
146
|
+
dragHint.classList.toggle('dimmed', hasDragged);
|
|
147
|
+
listEl.querySelectorAll('.crystal-list-item').forEach(bindItem);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
render();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import CrystalPanel from './components/CrystalPanel.astro';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
ui: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { ui } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<div class="tool-main-card" data-ui={JSON.stringify(ui)}>
|
|
12
|
+
<CrystalPanel labels={ui} />
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<script src="./client.ts"></script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
labels: Record<string, string>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { labels } = Astro.props;
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<link href="./watch-crystal-material-comparison.css" rel="stylesheet" />
|
|
10
|
+
|
|
11
|
+
<div class="crystal-layout">
|
|
12
|
+
<div class="crystal-list" id="crystal-list"></div>
|
|
13
|
+
<div class="crystal-card-wrap" id="crystal-card-wrap"></div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="crystal-drag-hint" id="crystal-drag-hint">
|
|
16
|
+
<span>{labels.dragHint || 'Drag'} </span>
|
|
17
|
+
<span class="drag-arrow">→</span>
|
|
18
|
+
<span> {labels.dragSub || 'crystals to compare'}</span>
|
|
19
|
+
</div>
|
|
20
|
+
<div id="crystal-fight"></div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ChronoToolEntry, ToolLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export type WatchCrystalMaterialComparisonUI = {
|
|
4
|
+
title: string;
|
|
5
|
+
subTitle: string;
|
|
6
|
+
hardness: string;
|
|
7
|
+
clarity: string;
|
|
8
|
+
impactResistance: string;
|
|
9
|
+
scratchResistance: string;
|
|
10
|
+
durability: string;
|
|
11
|
+
priceRange: string;
|
|
12
|
+
step1: string;
|
|
13
|
+
step2: string;
|
|
14
|
+
step3: string;
|
|
15
|
+
tipTitle: string;
|
|
16
|
+
tipContent: string;
|
|
17
|
+
dragHint: string;
|
|
18
|
+
dragSub: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type WatchCrystalMaterialComparisonLocaleContent = ToolLocaleContent<WatchCrystalMaterialComparisonUI>;
|
|
22
|
+
|
|
23
|
+
export const watchCrystalMaterialComparison: ChronoToolEntry<WatchCrystalMaterialComparisonUI> = {
|
|
24
|
+
id: 'watch-crystal-material-comparison',
|
|
25
|
+
icons: { bg: 'mdi:diamond-stone', fg: 'mdi:glass-cocktail' },
|
|
26
|
+
i18n: {
|
|
27
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
28
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
29
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
30
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
31
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
32
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
33
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
34
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
35
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
36
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
37
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
38
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
39
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
40
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
41
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { WithContext, Thing } from 'schema-dts';
|
|
2
|
+
import type { FAQItem, HowToStep } from '../../types';
|
|
3
|
+
|
|
4
|
+
function buildFAQ(faq: FAQItem[]): WithContext<Thing> {
|
|
5
|
+
return {
|
|
6
|
+
'@context': 'https://schema.org',
|
|
7
|
+
'@type': 'FAQPage',
|
|
8
|
+
'mainEntity': faq.map((f) => ({
|
|
9
|
+
'@type': 'Question',
|
|
10
|
+
'name': f.question,
|
|
11
|
+
'acceptedAnswer': {
|
|
12
|
+
'@type': 'Answer',
|
|
13
|
+
'text': f.answer,
|
|
14
|
+
},
|
|
15
|
+
})),
|
|
16
|
+
} as unknown as WithContext<Thing>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function buildApp(title: string): WithContext<Thing> {
|
|
20
|
+
return {
|
|
21
|
+
'@context': 'https://schema.org',
|
|
22
|
+
'@type': 'SoftwareApplication',
|
|
23
|
+
'name': title,
|
|
24
|
+
'operatingSystem': 'All',
|
|
25
|
+
'applicationCategory': 'UtilitiesApplication',
|
|
26
|
+
'browserRequirements': 'Requires HTML5. Requires JavaScript.',
|
|
27
|
+
} as unknown as WithContext<Thing>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildHowTo(title: string, howTo: HowToStep[]): WithContext<Thing> {
|
|
31
|
+
return {
|
|
32
|
+
'@context': 'https://schema.org',
|
|
33
|
+
'@type': 'HowTo',
|
|
34
|
+
'name': title,
|
|
35
|
+
'step': howTo.map((h) => ({
|
|
36
|
+
'@type': 'HowToStep',
|
|
37
|
+
'name': h.name,
|
|
38
|
+
'text': h.text,
|
|
39
|
+
})),
|
|
40
|
+
} as unknown as WithContext<Thing>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function buildSchemas(
|
|
44
|
+
title: string,
|
|
45
|
+
faq: FAQItem[],
|
|
46
|
+
howTo: HowToStep[]
|
|
47
|
+
): WithContext<Thing>[] {
|
|
48
|
+
return [buildFAQ(faq), buildApp(title), buildHowTo(title, howTo)];
|
|
49
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
2
|
+
import type { WatchCrystalMaterialComparisonUI } from '../entry';
|
|
3
|
+
import { bibliography } from '../bibliography';
|
|
4
|
+
import { buildSchemas } from '../helpers';
|
|
5
|
+
|
|
6
|
+
const faq = [
|
|
7
|
+
{ question: 'Welches Uhrenglas ist am kratzfestesten?', answer: 'Saphirglas ist mit einer Härte von 9 auf der Mohs-Skala am kratzfestesten - nur Diamant ist härter. Mineralglas (5) ist mittel, während Hesalit (2-3) leicht zerkratzt, aber poliert werden kann.' },
|
|
8
|
+
{ question: 'Kann ein zerkratztes Hesalitglas repariert werden?', answer: 'Ja, Kratzer in Hesalit können mit Polywatch in Minuten wegpoliert werden. Mineral- und Saphirgläser können nicht poliert werden und müssen bei Kratzern oder Bruch ersetzt werden.' },
|
|
9
|
+
{ question: 'Welches Glas ist am besten für Taucheruhren?', answer: 'Saphir ist der Standard für Taucheruhren aufgrund seiner Kratzfestigkeit und Haltbarkeit. Hesalit wird nicht zum Tauchen empfohlen.' },
|
|
10
|
+
];
|
|
11
|
+
const howTo = [
|
|
12
|
+
{ name: 'Kristall auswählen', text: 'Klicken Sie links auf einen Kristall, um seine Statistik-Karte rechts zu sehen.' },
|
|
13
|
+
{ name: 'Zwei Kristalle vergleichen', text: 'Ziehen Sie einen Kristall aus der Liste und legen Sie ihn auf einen anderen, um sie nebeneinander zu vergleichen.' },
|
|
14
|
+
{ name: 'Vergleich schließen', text: 'Klicken Sie auf "Close Comparison", um zur Einzelansicht zurückzukehren.' },
|
|
15
|
+
];
|
|
16
|
+
const title = 'Uhrenglas Vergleich: Hesalit vs Mineralglas vs Saphir';
|
|
17
|
+
|
|
18
|
+
export const content: ToolLocaleContent<WatchCrystalMaterialComparisonUI> = {
|
|
19
|
+
slug: 'uhrenglas-vergleich-hesalit-mineral-saphir',
|
|
20
|
+
title,
|
|
21
|
+
description: 'Vergleichen Sie Hesalit, Mineralglas und Saphir Uhrengläser mit interaktiven Statistik-Karten. Sehen Sie Härte, Klarheit, Schlagfestigkeit, Kratzfestigkeit und Haltbarkeit.',
|
|
22
|
+
ui: {
|
|
23
|
+
title: 'Uhrenglas Vergleich', subTitle: 'Interactive Crystal Stats', hardness: 'Härte', clarity: 'Klarheit',
|
|
24
|
+
impactResistance: 'Schlag', scratchResistance: 'Kratzer', durability: 'Haltbarkeit', priceRange: 'Preis',
|
|
25
|
+
step1: 'Klicken Sie links auf einen Kristall.', step2: 'Ziehen Sie einen auf einen anderen zum Vergleichen.',
|
|
26
|
+
step3: 'Klicken Sie auf Schließen.', tipTitle: 'Tipp',
|
|
27
|
+
tipContent: 'Die Gesamtwertung ist ein Durchschnitt aller Werte. Höher ist nicht immer besser - Hesalit hat die beste Schlagfestigkeit.',
|
|
28
|
+
dragHint: 'Ziehen', dragSub: 'zum Vergleichen',
|
|
29
|
+
},
|
|
30
|
+
seo: [
|
|
31
|
+
{ type: 'title', text: 'Uhrenglas Vergleich: Hesalit vs Mineralglas vs Saphir', level: 2 },
|
|
32
|
+
{ type: 'paragraph', html: 'Vergleichen Sie <strong>Hesalit, Mineralglas und Saphir</strong> Uhrengläser mit interaktiven Statistik-Karten. Sehen Sie Härte, Klarheit, Schlagfestigkeit, Kratzfestigkeit und Haltbarkeit auf einen Blick.' },
|
|
33
|
+
],
|
|
34
|
+
faq, bibliography, howTo, schemas: buildSchemas(title, faq, howTo),
|
|
35
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
2
|
+
import type { WatchCrystalMaterialComparisonUI } from '../entry';
|
|
3
|
+
import { bibliography } from '../bibliography';
|
|
4
|
+
import { buildSchemas } from '../helpers';
|
|
5
|
+
|
|
6
|
+
const faq = [
|
|
7
|
+
{
|
|
8
|
+
question: 'Which is the most scratch resistant watch crystal?',
|
|
9
|
+
answer: 'Sapphire crystal is the most scratch resistant with a hardness of 9 on the Mohs scale - only diamond is harder. It is virtually impossible to scratch in everyday use. Mineral glass (5) is moderately scratch resistant, while hesalite/acrylic (2-3) scratches very easily but can be polished out in minutes with Polywatch.',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
question: 'Can a scratched hesalite crystal be repaired?',
|
|
13
|
+
answer: 'Yes, hesalite (acrylic) is the only watch crystal that can be easily repaired. Minor scratches can be buffed out using a product like Polywatch in just a few minutes. This makes hesalite popular for vintage watches and the Omega Speedmaster. Mineral and sapphire crystals cannot be polished and must be replaced if scratched or shattered.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
question: 'Is sapphire crystal shatter proof?',
|
|
17
|
+
answer: 'No, sapphire crystal is not shatter proof. While it is extremely scratch resistant, it is more brittle than hesalite and can shatter on sharp impacts. Hesalite is actually the most impact-resistant crystal type - it will deform rather than shatter. Mineral glass sits in between, offering moderate impact resistance.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
question: 'Which watch crystal is best for a dive watch?',
|
|
21
|
+
answer: 'Sapphire is the standard for dive watches due to its scratch resistance and durability. Most professional dive watches use sapphire crystal because it can withstand the pressures of deep diving without scratching. Hesalite is not recommended for diving as it scratches easily and can deform under pressure, potentially compromising water resistance.',
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const howTo = [
|
|
26
|
+
{
|
|
27
|
+
name: 'Select a crystal type',
|
|
28
|
+
text: 'Click any crystal from the list on the left - its stats card will appear on the right with ratings for hardness, clarity, impact resistance, scratch resistance, and durability.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'Compare two crystals side by side',
|
|
32
|
+
text: 'Drag one crystal from the list and drop it onto another to start a side-by-side comparison. Both stat cards will appear so you can compare their ratings directly.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Close the comparison view',
|
|
36
|
+
text: 'Click the "Close comparison" button below the side-by-side view to return to a single crystal display. You can also click any crystal on the left to switch the main view.',
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const title = 'Watch Crystal Material Comparison: Hesalite vs Mineral Glass vs Sapphire';
|
|
41
|
+
|
|
42
|
+
export const content: ToolLocaleContent<WatchCrystalMaterialComparisonUI> = {
|
|
43
|
+
slug: 'watch-crystal-material-comparison',
|
|
44
|
+
title,
|
|
45
|
+
description: 'Compare hesalite, mineral glass, and sapphire watch crystals side by side with interactive stat cards. See hardness, clarity, impact resistance, scratch resistance, and durability ratings to choose the best crystal for your watch.',
|
|
46
|
+
ui: {
|
|
47
|
+
title: 'Crystal Material Comparison',
|
|
48
|
+
subTitle: 'Interactive Crystal Stats',
|
|
49
|
+
hardness: 'Hardness',
|
|
50
|
+
clarity: 'Clarity',
|
|
51
|
+
impactResistance: 'Impact',
|
|
52
|
+
scratchResistance: 'Scratch',
|
|
53
|
+
durability: 'Durability',
|
|
54
|
+
priceRange: 'Price',
|
|
55
|
+
step1: 'Click a crystal on the left to view its stats card.',
|
|
56
|
+
step2: 'Drag one crystal onto another to compare them side by side.',
|
|
57
|
+
step3: 'Click close to return to single crystal view.',
|
|
58
|
+
tipTitle: 'Tip',
|
|
59
|
+
tipContent: 'Overall rating is an average of all five stats. Higher overall does not mean it is the best for every use case - hesalite has the highest impact resistance while sapphire is best for scratch resistance.',
|
|
60
|
+
dragHint: 'Drag',
|
|
61
|
+
dragSub: 'crystals to compare',
|
|
62
|
+
},
|
|
63
|
+
seo: [
|
|
64
|
+
{ type: 'title', text: 'Hesalite vs Mineral vs Sapphire: Watch Crystal Comparison Guide', level: 2 },
|
|
65
|
+
{ type: 'paragraph', html: 'Choosing the right <strong>watch crystal</strong> is one of the most important decisions when buying or restoring a watch. This guide compares <strong>hesalite (acrylic), mineral glass, and sapphire crystal</strong> across hardness, clarity, impact resistance, scratch resistance, durability, and price.' },
|
|
66
|
+
{ type: 'title', text: 'Hesalite Crystal (Acrylic / Plexiglass)', level: 3 },
|
|
67
|
+
{ type: 'paragraph', html: 'Hesalite is the original watch crystal material, used since the 1930s. It is soft (2-3 Mohs) and scratches easily, but these scratches can be quickly polished out. It offers the best impact resistance - it flexes rather than shatters. Hesalite can be formed into extreme domes, giving vintage watches their characteristic look. Famous example: Omega Speedmaster Professional - the watch worn on the Moon.' },
|
|
68
|
+
{ type: 'title', text: 'Mineral Glass (Tempered)', level: 3 },
|
|
69
|
+
{ type: 'paragraph', html: 'Mineral glass is made from silicon dioxide and then tempered (heat-treated) to increase its strength. At 5 on the Mohs scale, it is harder than hesalite but still susceptible to scratches. It offers moderate impact resistance but can shatter on hard impacts. Commonly found in mid-range watches from Seiko, Citizen, and Orient.' },
|
|
70
|
+
{ type: 'title', text: 'Sapphire Crystal (Synthetic Corundum)', level: 3 },
|
|
71
|
+
{ type: 'paragraph', html: 'Sapphire crystal is made from lab-grown corundum - the same mineral as natural sapphire. At 9 on the Mohs scale, it is virtually scratch-proof and offers the best optical clarity. However, it is more brittle and can shatter on sharp impacts. It is also the most expensive option and difficult to form into high domes. The standard for luxury watches.' },
|
|
72
|
+
{ type: 'title', text: 'Crystal Comparison Table', level: 3 },
|
|
73
|
+
{
|
|
74
|
+
type: 'table', headers: ['Property', 'Hesalite', 'Mineral Glass', 'Sapphire'], rows: [
|
|
75
|
+
['Mohs Hardness', '2-3/10', '5/10', '9/10'],
|
|
76
|
+
['Clarity', '4/10', '7/10', '10/10'],
|
|
77
|
+
['Impact Resistance', '5/10 (Best)', '3/10', '2/10'],
|
|
78
|
+
['Scratch Resistance', '1/10', '5/10', '10/10'],
|
|
79
|
+
['Repairable', 'Yes (polish)', 'No (replace)', 'No (replace)'],
|
|
80
|
+
['Dome Possible', 'Yes, extreme', 'Limited', 'Limited'],
|
|
81
|
+
['Price Range', '$5 - $30', '$10 - $50', '$30 - $200+'],
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{ type: 'diagnostic', variant: 'info', title: 'Crystal Selection Guide', icon: 'mdi:diamond-stone', badge: 'REFERENCE', html: 'For a <strong>tool watch or daily beater</strong>, choose sapphire for scratch resistance. For a <strong>vintage restoration or budget build</strong>, hesalite offers authentic looks and repairability. <strong>Mineral glass</strong> is the budget-friendly middle ground found in most entry-level automatics.' },
|
|
85
|
+
],
|
|
86
|
+
faq,
|
|
87
|
+
bibliography,
|
|
88
|
+
howTo,
|
|
89
|
+
schemas: buildSchemas(title, faq, howTo),
|
|
90
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
2
|
+
import type { WatchCrystalMaterialComparisonUI } from '../entry';
|
|
3
|
+
import { bibliography } from '../bibliography';
|
|
4
|
+
import { buildSchemas } from '../helpers';
|
|
5
|
+
|
|
6
|
+
const faq = [
|
|
7
|
+
{ question: '¿Qué cristal de reloj es más resistente a los arañazos?', answer: 'El cristal de zafiro es el más resistente con una dureza de 9 en la escala de Mohs - solo el diamante es más duro. El mineral (5) es moderado, mientras que el hesalita (2-3) se raya fácilmente pero se puede pulir.' },
|
|
8
|
+
{ question: '¿Se puede reparar un cristal de hesalita rayado?', answer: 'Sí, los arañazos del hesalita se pueden pulir con Polywatch en minutos. Los cristales minerales y de zafiro no se pueden pulir y deben reemplazarse.' },
|
|
9
|
+
{ question: '¿Qué cristal es mejor para un reloj de buceo?', answer: 'El zafiro es el estándar para relojes de buceo por su resistencia a arañazos y durabilidad. El hesalita no se recomienda para bucear.' },
|
|
10
|
+
];
|
|
11
|
+
const howTo = [
|
|
12
|
+
{ name: 'Seleccionar un cristal', text: 'Haga clic en un cristal a la izquierda para ver su ficha de estadísticas a la derecha.' },
|
|
13
|
+
{ name: 'Comparar dos cristales', text: 'Arrastre un cristal de la lista y suéltelo sobre otro para compararlos lado a lado.' },
|
|
14
|
+
{ name: 'Cerrar comparación', text: 'Haga clic en "Close Comparison" para volver a la vista individual.' },
|
|
15
|
+
];
|
|
16
|
+
const title = 'Comparativa de Cristales de Reloj: Hesalita vs Mineral vs Zafiro';
|
|
17
|
+
|
|
18
|
+
export const content: ToolLocaleContent<WatchCrystalMaterialComparisonUI> = {
|
|
19
|
+
slug: 'comparativa-cristales-reloj-hesalita-mineral-zafiro',
|
|
20
|
+
title,
|
|
21
|
+
description: 'Compare cristales de reloj de hesalita, mineral y zafiro con tarjetas de estadísticas interactivas. Vea dureza, claridad, resistencia al impacto, resistencia a arañazos y durabilidad.',
|
|
22
|
+
ui: {
|
|
23
|
+
title: 'Comparativa de Cristales', subTitle: 'Interactive Crystal Stats', hardness: 'Dureza', clarity: 'Claridad',
|
|
24
|
+
impactResistance: 'Impacto', scratchResistance: 'Arañazos', durability: 'Durabilidad', priceRange: 'Precio',
|
|
25
|
+
step1: 'Haga clic en un cristal a la izquierda.', step2: 'Arrastre uno sobre otro para comparar.',
|
|
26
|
+
step3: 'Haga clic en Cerrar.', tipTitle: 'Consejo',
|
|
27
|
+
tipContent: 'La valoración general es un promedio de todas las estadísticas. Más alto no siempre es mejor - el hesalita tiene la mejor resistencia al impacto.',
|
|
28
|
+
dragHint: 'Arrastrar', dragSub: 'para comparar',
|
|
29
|
+
},
|
|
30
|
+
seo: [
|
|
31
|
+
{ type: 'title', text: 'Comparativa de Cristales de Reloj: Hesalita vs Mineral vs Zafiro', level: 2 },
|
|
32
|
+
{ type: 'paragraph', html: 'Compare <strong>hesalita, mineral y zafiro</strong> con tarjetas de estadísticas interactivas. Vea dureza, claridad, resistencia al impacto, arañazos y durabilidad.' },
|
|
33
|
+
],
|
|
34
|
+
faq, bibliography, howTo, schemas: buildSchemas(title, faq, howTo),
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
2
|
+
import type { WatchCrystalMaterialComparisonUI } from '../entry';
|
|
3
|
+
import { bibliography } from '../bibliography';
|
|
4
|
+
import { buildSchemas } from '../helpers';
|
|
5
|
+
|
|
6
|
+
const faq = [
|
|
7
|
+
{ question: 'Quel verre de montre est le plus résistant aux rayures?', answer: 'Le verre saphir est le plus résistant avec une dureté de 9 sur l\'échelle de Mohs - seul le diamant est plus dur. Le verre minéral (5) est modéré, tandis que l\'hesalite (2-3) se raye facilement mais peut être poli.' },
|
|
8
|
+
{ question: 'Peut-on réparer un verre hesalite rayé?', answer: 'Oui, les rayures sur l\'hesalite peuvent être polies avec Polywatch en quelques minutes. Les verres minéraux et saphir ne peuvent pas être polis et doivent être remplacés.' },
|
|
9
|
+
{ question: 'Quel verre est le meilleur pour une montre de plongée?', answer: 'Le saphir est la référence pour les montres de plongée pour sa résistance aux rayures et sa durabilité. L\'hesalite n\'est pas recommandé pour la plongée.' },
|
|
10
|
+
];
|
|
11
|
+
const howTo = [
|
|
12
|
+
{ name: 'Sélectionner un verre', text: 'Cliquez sur un verre à gauche pour voir sa fiche de statistiques à droite.' },
|
|
13
|
+
{ name: 'Comparer deux verres', text: 'Faites glisser un verre depuis la liste et déposez-le sur un autre pour les comparer côte à côte.' },
|
|
14
|
+
{ name: 'Fermer la comparaison', text: 'Cliquez sur "Close Comparison" pour revenir à la vue unique.' },
|
|
15
|
+
];
|
|
16
|
+
const title = 'Comparaison de Verres de Montre: Hesalite vs Minéral vs Saphir';
|
|
17
|
+
|
|
18
|
+
export const content: ToolLocaleContent<WatchCrystalMaterialComparisonUI> = {
|
|
19
|
+
slug: 'comparaison-verres-montre-hesalite-mineral-saphir',
|
|
20
|
+
title,
|
|
21
|
+
description: 'Comparez les verres de montre hesalite, minéral et saphir avec des fiches de statistiques interactives. Voyez la dureté, la clarté, la résistance aux chocs et aux rayures.',
|
|
22
|
+
ui: {
|
|
23
|
+
title: 'Comparaison de Verres', subTitle: 'Interactive Crystal Stats', hardness: 'Dureté', clarity: 'Clarté',
|
|
24
|
+
impactResistance: 'Chocs', scratchResistance: 'Rayures', durability: 'Résistance', priceRange: 'Prix',
|
|
25
|
+
step1: 'Cliquez sur un verre à gauche.', step2: 'Glissez-en un sur un autre pour comparer.',
|
|
26
|
+
step3: 'Cliquez sur Fermer.', tipTitle: 'Conseil',
|
|
27
|
+
tipContent: 'La note globale est une moyenne de toutes les stats. Plus haut ne signifie pas meilleur pour tout - l\'hesalite a la meilleure résistance aux chocs.',
|
|
28
|
+
dragHint: 'Glisser', dragSub: 'pour comparer',
|
|
29
|
+
},
|
|
30
|
+
seo: [
|
|
31
|
+
{ type: 'title', text: 'Comparaison de Verres de Montre: Hesalite vs Minéral vs Saphir', level: 2 },
|
|
32
|
+
{ type: 'paragraph', html: 'Comparez <strong>hesalite, minéral et saphir</strong> avec des fiches de statistiques interactives. Dureté, clarté, résistance aux chocs et aux rayures.' },
|
|
33
|
+
],
|
|
34
|
+
faq, bibliography, howTo, schemas: buildSchemas(title, faq, howTo),
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
2
|
+
import type { WatchCrystalMaterialComparisonUI } from '../entry';
|
|
3
|
+
import { bibliography } from '../bibliography';
|
|
4
|
+
import { buildSchemas } from '../helpers';
|
|
5
|
+
|
|
6
|
+
const faq = [
|
|
7
|
+
{ question: 'Kristal jam tangan mana yang paling tahan gores?', answer: 'Kristal safir adalah yang paling tahan gores dengan kekerasan 9 pada skala Mohs - hanya berlian yang lebih keras. Mineral (5) sedang, sementara hesalit (2-3) mudah tergores tetapi bisa dipoles.' },
|
|
8
|
+
{ question: 'Bisakah kristal hesalit yang tergores diperbaiki?', answer: 'Ya, goresan pada hesalit dapat dipoles dengan Polywatch dalam hitungan menit. Kristal mineral dan safir tidak bisa dipoles dan harus diganti.' },
|
|
9
|
+
{ question: 'Kristal mana yang terbaik untuk jam tangan selam?', answer: 'Safir adalah standar untuk jam tangan selam karena ketahanan gores dan daya tahannya. Hesalit tidak disarankan untuk menyelam.' },
|
|
10
|
+
];
|
|
11
|
+
const howTo = [
|
|
12
|
+
{ name: 'Pilih kristal', text: 'Klik kristal di kiri untuk melihat kartu statistiknya di kanan.' },
|
|
13
|
+
{ name: 'Bandingkan dua kristal', text: 'Seret kristal dari daftar dan jatuhkan ke kristal lain untuk membandingkannya.' },
|
|
14
|
+
{ name: 'Tutup perbandingan', text: 'Klik "Close Comparison" untuk kembali ke tampilan tunggal.' },
|
|
15
|
+
];
|
|
16
|
+
const title = 'Perbandingan Kristal Jam Tangan: Hesalite vs Mineral vs Safir';
|
|
17
|
+
|
|
18
|
+
export const content: ToolLocaleContent<WatchCrystalMaterialComparisonUI> = {
|
|
19
|
+
slug: 'perbandingan-kristal-jam-tangan-hesalit-mineral-safir',
|
|
20
|
+
title,
|
|
21
|
+
description: 'Bandingkan kristal jam tangan hesalit, mineral, dan safir dengan kartu statistik interaktif. Lihat kekerasan, kejelasan, ketahanan benturan, dan gores.',
|
|
22
|
+
ui: {
|
|
23
|
+
title: 'Perbandingan Kristal', subTitle: 'Interactive Crystal Stats', hardness: 'Kekerasan', clarity: 'Kejelasan',
|
|
24
|
+
impactResistance: 'Benturan', scratchResistance: 'Gores', durability: 'Daya Tahan', priceRange: 'Harga',
|
|
25
|
+
step1: 'Klik kristal di kiri.', step2: 'Seret satu ke atas yang lain untuk membandingkan.',
|
|
26
|
+
step3: 'Klik Tutup.', tipTitle: 'Tips',
|
|
27
|
+
tipContent: 'Peringkat keseluruhan adalah rata-rata semua statistik. Lebih tinggi tidak selalu lebih baik - hesalit memiliki ketahanan benturan terbaik.',
|
|
28
|
+
dragHint: 'Seret', dragSub: 'untuk membandingkan',
|
|
29
|
+
},
|
|
30
|
+
seo: [
|
|
31
|
+
{ type: 'title', text: 'Perbandingan Kristal Jam Tangan: Hesalit vs Mineral vs Safir', level: 2 },
|
|
32
|
+
{ type: 'paragraph', html: 'Bandingkan <strong>hesalit, mineral, dan safir</strong> dengan kartu statistik interaktif.' },
|
|
33
|
+
],
|
|
34
|
+
faq, bibliography, howTo, schemas: buildSchemas(title, faq, howTo),
|
|
35
|
+
};
|