aboutsummaryrefslogtreecommitdiff
path: root/src/components/HelpModal.vue
blob: 5dc9ff3608e07b1fbd0537d5429c86fceaa825f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
<template>
<div class="fixed left-0 top-0 w-full h-full bg-black/40" @click="onClose" ref="rootRef">
	<div class="absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2
		w-[90%] max-w-[16cm] max-h-[80%] overflow-auto" :style="styles">
		<close-icon @click.stop="onClose" ref="closeRef"
			class="absolute top-1 right-1 md:top-2 md:right-2 w-8 h-8 hover:cursor-pointer"/>
		<h1 class="text-center text-xl sm:text-2xl font-bold pt-2 pb-1">Help</h1>
		<div class="flex flex-col gap-2 p-2">
			<s-collapsible :class="scClasses">
				<template #summary="slotProps">
					<div :class="scSummaryClasses">
						<down-icon :class="slotProps.open ? downIconExpandedClasses : downIconClasses"/>
						Visual Display
					</div>
				</template>
				<template #content>
					<div :class="contentClasses" class="space-y-3">
						<p>
							Initially, the main area contains one timeline, with ticks representing evenly spaced
							points in time. A square represents a min or max date. '1k BC' means
							1000 BC. 'mya' and 'bya' mean millions and billions of years ago.
						</p>
						<img src="/timeline.png" alt="Timeline with events"
							class="border border-stone-300 rounded mx-auto md:mx-0 md:shrink-0"/>
						<p>
							Events are shown as labelled images. Blue borders indicate
							discovery events. This is so that events like the discovery of Andromeda
							don't look the same as the event of its creation.
						</p>
						<p>
							Events are linked to points on the timeline that match their 'start date'.
							For a person, this is a date of birth. For a book, this is a date of publication.
							A dashed line indicates imprecision.
							{{touchDevice ? 'Tap' : 'Click'}} on an event to bring up more details.
						</p>
						<p>
							The timeline also has varying 'thickness', which indicates how many events
							are present between ticks.
							There are four levels, indicating counts of zero to over a thousand.
						</p>
						<p>
							The + button at the top right adds another timeline, if there's enough space.
						</p>
						<p>
							The bar at the {{vert ? 'right' : 'bottom'}} represents the full range of
							possible dates. Each timeline's bounds are displayed as a yellow subregion.
							Timelines will often look very thin, as the whole bar spans billions of years.
						</p>
					</div>
				</template>
			</s-collapsible>

			<s-collapsible :class="scClasses">
				<template #summary="slotProps">
					<div :class="scSummaryClasses">
						<down-icon :class="slotProps.open ? downIconExpandedClasses : downIconClasses"/>
						Other Features
					</div>
				</template>
				<template #content>
					<div :class="contentClasses">
						<h1 :class="contentH1Classes">Keyboard Shortcuts</h1>
						<ul :class="contentULClasses">
							<li>
								<span class="font-bold">{{vert ? 'Up': 'Left'}}</span> and
								<span class="font-bold">{{vert ? 'Down': 'Right'}}</span> pan the timeline
							</li>
							<li>
								<span class="font-bold">Shift-{{vert ? 'Left' : 'Up'}}</span> and
								<span class="font-bold">Shift-{{vert ? 'Right' : 'Down'}}</span>
								zoom in and out
							</li>
							<li>
								<span class="font-bold">Plus</span> and <span class="font-bold">Delete</span>
								add and remove timelines
							</li>
							<li>
								<span class="font-bold">{{vert ? 'Left' : 'Up'}}</span> and
								<span class="font-bold">{{vert ? 'Right' : 'Down'}}</span>
								switch between timelines
							</li>
							<li><span class="font-bold">Ctrl-F</span> opens the search bar</li>
							<li><span class="font-bold">Esc</span> closes an open pane</li>
						</ul>
						<br/>
						<h1 :class="contentH1Classes">Settings</h1>
						<ul :class="contentULClasses">
							<li>
								<h2 :class="contentH2Classes">Categories</h2>
								<p>
									Allows filtering of displayed events by category. Examples include:
								</p>
								<ul :class="contentInnerULClasses">
									<li><span class="font-bold">Event:</span> wars, disasters, celebrations</li>
									<li><span class="font-bold">Place:</span> cities, countries, galaxies</li>
									<li><span class="font-bold">Person:</span> writers, scientists, leaders</li>
									<li><span class="font-bold">Organism:</span> dinosaurs, insects, plants</li>
									<li>
										<span class="font-bold">Work:</span> books, movies, video games
									</li>
									<li><span class="font-bold">Discovery:</span> inventions, ideas, places</li>
								</ul>
								<p class="text-xs md:text-sm text-stone-500 py-1">
									(Unfortunately, timeline thickness isn't yet indicative of filtered events)
								</p>
							</li>
							<li>
								<h2 :class="contentH2Classes">Display</h2>
								<ul :class="contentInnerULClasses">
									<li><span class="font-bold">Only events with images:</span>
										If enabled, only about 20% of events are shown</li>
									<li><span class="font-bold">Minor tick text:</span>
										Toggles labels for small-sized ticks</li>
									<li><span class="font-bold">Event density:</span>
										Toggles timeline thickness</li>
									<li><span class="font-bold">Event lines:</span>
										Toggles lines linking events to timelines</li>
									<li><span class="font-bold">Baseline:</span>
										Toggles the bar representing the full date range</li>
								</ul>
							</li>
							<li>
								<h2 :class="contentH2Classes">Input</h2>
								<ul :class="contentInnerULClasses">
									<li><span class="font-bold">Pan ratio:</span>
										Higher values mean faster panning</li>
									<li><span class="font-bold">Zoom ratio:</span>
										Higher values mean faster zooming</li>
								</ul>
							</li>
						</ul>
						<p class="mt-2">
							{{touchDevice ? 'Tapping' : 'Clicking'}} on
							a slider's label resets it to its default value.
						</p>
					</div>
				</template>
			</s-collapsible>

			<s-collapsible :class="scClasses">
				<template #summary="slotProps">
					<div :class="scSummaryClasses">
						<down-icon :class="slotProps.open ? downIconExpandedClasses : downIconClasses"/>
						Licensing and Credits
					</div>
				</template>
				<template #content>
					<div :class="contentClasses">
						<p>
							The source code is available on
							<a href="https://github.com/terry06890/chrona" :style="aStyles">GitHub</a>, under the
							<a href="https://github.com/terry06890/tilo/blob/main/LICENCE.txt"
									:style="aStyles">MIT Licence</a>
						</p>
						<br/>
						<h1 :class="contentH1Classes">Data Sources</h1>
						<ul :class="contentULClasses">
							<li>
								Event data was obtained from the
								<a href="https://dumps.wikimedia.org/wikidatawiki/entities/" :style="aStyles">
									Wikidata dump</a> for 23/08/22. About 350,000 events were extracted.
							</li>
							<li>
								Event descriptions, images, and popularity were obtained via the
								<a href="https://dumps.wikimedia.org/enwiki/" :style="aStyles">Wikimedia dump</a>
								for 01/05/22.
								Wikipedia page content is available under
								<a href="https://creativecommons.org/licenses/by-sa/3.0/" :style="aStyles"
									>CC BY-SA 3.0</a>.
								For the source of a specific event's image, look in its info pane.
							</li>
						</ul>
						<br/>
						<div>
							<h1 :class="contentH1Classes">Other Credits</h1>
							<ul :class="contentULClasses">
								<li>
									The UI was mostly coded in
									<a href="https://www.typescriptlang.org/" :style="aStyles">Typescript</a>,
									and built wth <a href="https://vuejs.org/" :style="aStyles">Vue</a>,
									<a href="https://vitejs.dev/" :style="aStyles">Vite</a> &amp;
									<a href="https://pinia.vuejs.org/" :style="aStyles">Pinia</a>
								</li>
								<li>
									Tree data was processed using
									<a href="https://www.python.org/" :style="aStyles">Python</a>,
									and stored using
									<a href="https://www.sqlite.org/index.html" :style="aStyles">Sqlite</a>
								</li>
								<li>
									Styling was enhanced using
									<a href="https://tailwindcss.com/" :style="aStyles">Tailwind</a>
								</li>
								<li>
									The font is <a href="https://design.ubuntu.com/font/" :style="aStyles">Ubuntu Font</a>,
									licensed under
									<a href="https://ubuntu.com/legal/font-licence"
										:style="aStyles">Ubuntu font licence</a>
								</li>
								<li>Icons were used from
									<a href="https://feathericons.com/" :style="aStyles">Feathericons</a>
									and <a href="https://ionic.io/ionicons" :style="aStyles">Ionicons</a>,
									both under MIT License
								</li>
								<li>
									Images were cropped using
									<a href="https://github.com/jwagner/smartcrop.js" :style="aStyles">Smartcrop</a>
								</li>
							</ul>
						</div>
					</div>
				</template>
			</s-collapsible>

			<s-collapsible :class="scClasses">
				<template #summary="slotProps">
					<div :class="scSummaryClasses">
						<down-icon :class="slotProps.open ? downIconExpandedClasses : downIconClasses"/>
						FAQs
					</div>
				</template>
				<template #content>
					<div :class="contentClasses">
						<h1 :class="contentH1Classes">How accurate is the information?</h1>
						<div class="space-y-3">
							<p>
								Event data was extracted by looking for objects in the Wikidata knowledge graph that
								have certain properties. These are not always consistent or accurate.
								For example, an event's date might be encoded using a 'start time',
								'temporal range start', or 'earliest date' property, without a clear pattern.
							</p>
							<p>
								Also, some properties have unclear definitions. For example, in looking for
								creative works, a 'genre' property was used. But as it turns out, sometimes
								fictional characters or places will also have that property, which can
								cause unexpected results (like having Hogwarts displayed as a work).
							</p>
							<p>
								As for the short descriptions, they were extracted from marked-up Wikipedia content
								using imprecise heuristics. Many have leftover fragments of code, or incomplete
								sentences.
							</p>
						</div>
						<br/>
						<h1 :class="contentH1Classes">
							In the info boxes, what do terms like "1st century BC" and "O.S." mean?</h1>
						<div class="space-y-3">
							<p>
								Each event can have both a start and end date, both of which may be imprecise.
								For example, the start may range between years 1901 and 2000, which corresponds to the
								20th century. Similarly, the 1st century BC represents years 99 BC to 1 BC.
								There is no year 0 BC, because 1 BC is directly followed by 1 AD.
							</p>
							<p>
								Decades are like centuries, and have ranges like 1701 to 1710, generally ranging from
								a year ending with one up to a year ending with zero. Other scales are
								different. "2nd millenium" means 1000 to 1999. And "About 2 million years ago" means
								2,000,000 BC to 1,000,001 BC.
							</p>
							<p>
								For dates like "1st Jan 1600 (O.S.)", the "O.S." means
								<a href="https://en.wikipedia.org/wiki/Old_Style_and_New_Style_dates" :style="aStyles">
									Old Style</a>, and the date is
								in the Julian Calendar (as opposed to the Gregorian Calendar). These tend to
								appear for events in certain countries between 1550 and 1950.
							</p>
						</div>
						<br/>
						<h1 :class="contentH1Classes">Why am I sometimes unable to zoom into a year?</h1>
						<p>
							Calendar dates are only valid starting from the year {{-MIN_CAL_YEAR}} BC.
							This is because
							<a href="https://en.wikipedia.org/wiki/Julian_day" :style="aStyles">Julian day numbers</a>
							are used to encode calendar dates.
							Before this point, zooming into sub-yearly scales is disabled.
						</p>
						<br/>
						<h1 :class="contentH1Classes">Why are there so many celebrities?</h1>
						<p>
							Events are chosen for display by popularity, which is determined using Wikipedia
							page view counts. Celebrities tend to rank highly with this metric, regardless
							of historical importance. This might be adjusted in future.
						</p>
						<br/>
						<h1 :class="contentH1Classes">Why do some people have their faces clipped out?</h1>
						<p>
							Images from Wikipedia were cropped into squares semi-automatically. This sometimes
							ends badly, with the person's chest or headwear being placed in center focus.
						</p>
					</div>
				</template>
			</s-collapsible>
		</div>
		<p class="text-right text-xs md:text-sm text-stone-500 pr-2 pb-2">
			Last updated 28/01/23
		</p>
	</div>
</div>
</template>

<script setup lang="ts">
import {ref, computed} from 'vue';

import SButton from './SButton.vue';
import SCollapsible from './SCollapsible.vue';
import CloseIcon from './icon/CloseIcon.vue';
import DownIcon from './icon/DownIcon.vue';

import {MIN_DATE, MAX_DATE, MIN_CAL_YEAR, dateToDisplayStr, dateToYearStr} from '../lib';
import {useStore} from '../store';

const rootRef = ref(null as HTMLDivElement | null)
const closeRef = ref(null as typeof CloseIcon | null);

const store = useStore();
const touchDevice = computed(() => store.touchDevice)

const props = defineProps({
	vert: {type: Boolean, required: true},
});

const emit = defineEmits(['close']);

// ========== Event handlers ==========

function onClose(evt: Event){
	if (evt.target == rootRef.value || closeRef.value!.$el.contains(evt.target)){
		emit('close');
	}
}

// ========== For styles ==========

const scClasses = 'border border-stone-400 rounded';
const scSummaryClasses = 'relative text-center p-1 bg-stone-300 hover:brightness-90 hover:bg-amber-200 md:p-2';
const downIconClasses = 'absolute w-6 h-6 my-auto mx-1 transition-transform duration-300';
const downIconExpandedClasses = computed(() => downIconClasses + ' -rotate-90');
const contentClasses = 'py-2 px-2 text-sm md:text-base';
const contentH1Classes = 'text-lg font-bold mb-2';
const contentH2Classes = 'font-bold';
const contentULClasses = 'list-disc pl-4'
const contentInnerULClasses = 'list-[circle] pl-4'

const styles = computed(() => ({
	backgroundColor: store.color.bgAlt,
	borderRadius: store.borderRadius + 'px',
}));

const aStyles = computed(() => ({
	color: store.color.altDark2,
}));
</script>