-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
335 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Head, Html, Main, NextScript } from 'next/document'; | ||
|
||
export default function Document() { | ||
return ( | ||
<Html> | ||
<Head> | ||
<link href="https://fonts.googleapis.com" rel="preconnect" /> | ||
<link | ||
crossOrigin="anonymous" | ||
href="https://fonts.gstatic.com" | ||
rel="preconnect" | ||
/> | ||
<link | ||
href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,700;1,400;1,700&display=swap" | ||
rel="stylesheet" | ||
/> | ||
</Head> | ||
<body> | ||
<Main /> | ||
<NextScript /> | ||
</body> | ||
</Html> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
html, body, :root { | ||
margin: 0; | ||
padding: 0; | ||
} | ||
|
||
body { | ||
font-family: 'Lora', serif; | ||
} | ||
|
||
a { | ||
font-style: italic; | ||
color: currentColor; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
.dottedDivider { | ||
display: grid; | ||
grid: ". line-left . text . line-right ." min-content/.2em 1fr 2rem min-content 2rem 1fr .2em | ||
} | ||
|
||
.dottedDivider::before, .dottedDivider::after { | ||
border-top: 1px solid currentColor; | ||
content: ""; | ||
height: 0; | ||
margin: auto; | ||
width: 100%; | ||
} | ||
|
||
.dottedDivider::before { | ||
grid-area: line-left; | ||
} | ||
|
||
.dottedDivider::after { | ||
grid-area: line-right; | ||
} | ||
|
||
.dottedDivider > * { | ||
font-weight: initial; | ||
grid-area: text; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
.year { | ||
display: grid; | ||
grid: | ||
'....... ......... ........ ........... ....... .......... .....' 1em | ||
'....... line-left ........ year ....... line-right .....' | ||
'....... line-left ........ age ....... line-right .....' | ||
'....... ......... ........ ........... ....... .......... .....' 1em | ||
'....... content content content content content .....' | ||
/ .2em 1fr 1em min-content 1em 1fr .2em | ||
} | ||
|
||
.year::before, .year::after { | ||
border-top: 1px solid currentColor; | ||
content: ""; | ||
height: 0; | ||
margin: auto; | ||
width: 100%; | ||
} | ||
|
||
.year::before { | ||
grid-area: line-left; | ||
} | ||
|
||
.year::after { | ||
grid-area: line-right; | ||
} | ||
|
||
|
||
|
||
.month { | ||
display: grid; | ||
grid: | ||
|
||
'........ ....... ..... ....... ......' .2em | ||
'........ ....... month ....... ......' | ||
'........ ....... ....... ....... ......' .2em | ||
'........ content content content ......' | ||
'........ ....... ....... ....... ......' .2em | ||
/.5em 1fr min-content 1fr .5em; | ||
width: 30em; | ||
} | ||
|
||
.monthName { | ||
grid-area: month; | ||
font-style: italic; | ||
} | ||
|
||
.event { | ||
max-width: 30em; | ||
margin-bottom: 1em; | ||
width: 100%; | ||
} | ||
|
||
.event::before { | ||
margin-left: 3em; | ||
} | ||
|
||
.yearIndicator, .ageIndicator { | ||
margin: auto; | ||
} | ||
|
||
.yearIndicator { | ||
grid-area: year; | ||
} | ||
|
||
.ageIndicator { | ||
grid-area: age; | ||
} | ||
|
||
.content { | ||
grid-area: content; | ||
display: flex; | ||
flex-wrap: wrap; | ||
justify-content: space-evenly; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import Immutable from 'immutable'; | ||
import React from 'react'; | ||
import * as Bio from 'project/zemn.me/bio'; | ||
import * as lang from 'ts/react/lang'; | ||
import style from 'project/zemn.me/next/pages/timeline.module.css'; | ||
|
||
|
||
const numerals = [ | ||
[3000, 'MMM'], | ||
[2000, 'MM'], | ||
[1000, 'M'], | ||
[900, 'CM'], | ||
[800, 'DCCC'], | ||
[700, 'DCC'], | ||
[600, 'DC'], | ||
[500, 'D'], | ||
[400, 'CD'], | ||
[300, 'CCC'], | ||
[200, 'CC'], | ||
[100, 'C'], | ||
[90, 'XC'], | ||
[80, 'LXXX'], | ||
[70, 'LXX'], | ||
[60, 'LX'], | ||
[50, 'L'], | ||
[40, 'XL'], | ||
[30, 'XXX'], | ||
[20, 'XX'], | ||
[10, 'X'], | ||
[9, 'IX'], | ||
[8, 'VIII'], | ||
[7, 'VII'], | ||
[6, 'VI'], | ||
[5, 'V'], | ||
[4, 'IV'], | ||
[3, 'III'], | ||
[2, 'II'], | ||
[1, 'I'], | ||
] as const; | ||
|
||
const romanize = (n: number) => { | ||
const on = n; | ||
const parts: string[] = []; | ||
while (n > 0) { | ||
for (const [value, sym] of numerals) { | ||
if (n < value) continue; | ||
parts.push(sym); | ||
n -= value; | ||
break; | ||
} | ||
} | ||
|
||
return parts.join(''); | ||
}; | ||
|
||
|
||
/** | ||
* Given a map that contains a set, set a single item, expanding or creating | ||
* the set if needed. | ||
* @param v the map | ||
* @param key the key in the map | ||
* @param value the item to set | ||
* @returns the same map that was put in | ||
*/ | ||
function setManyMap<K, V>( | ||
v: Immutable.OrderedMap<K, Immutable.List<V>>, | ||
key: K, | ||
value: V | ||
): Immutable.OrderedMap<K, Immutable.List<V>> { | ||
return v.set(key, v.get(key, Immutable.List<V>()).concat(value)); | ||
} | ||
|
||
function groupBy<T, Q>( | ||
i: Iterable<T>, | ||
select: (v: T) => Q | ||
): Immutable.Map<Q, Immutable.List<T>> { | ||
let m = Immutable.OrderedMap<Q, Immutable.List<T>>(); | ||
for (const v of i) m = setManyMap(m, select(v), v); | ||
|
||
return m; | ||
} | ||
|
||
function Event({event: e}: {event: Bio.Event}) { | ||
return <div className={style.event}> | ||
<a href={e.url?.toString()} lang={lang.get(e.title)}> | ||
{lang.text(e.title)} | ||
</a> | ||
|
||
{" "} | ||
|
||
{ | ||
e.description | ||
? <span lang={lang.get(e.description)}> | ||
{lang.text(e.description)} | ||
</span> | ||
: null | ||
} | ||
</div> | ||
} | ||
|
||
function Month({month, events}: { month: string, events: Iterable<Bio.Event>}) { | ||
return <div className={style.month}> | ||
<header className={style.monthName} lang="en-GB"> { /* <- this needs to be set to the correct language */ } | ||
{month} | ||
</header> | ||
<div className={style.content}> | ||
{ | ||
[...events].map((e, i) => <Event event={e} key={i}/>) | ||
} | ||
</div> | ||
</div> | ||
} | ||
|
||
function Year({year, months}: {year: string, months: Immutable.OrderedMap<string, Immutable.List<Bio.Event>> }) { | ||
return <div className={style.year}> | ||
<div className={style.yearIndicator}>{year}</div> | ||
<div className={style.ageIndicator}>{romanize((months.first(undefined)?.first()?.date.getFullYear() ?? 0) - 1994)}</div> | ||
|
||
<div className={style.content}> | ||
{ | ||
[...months].map(([month, events], i) => <Month month={month} events={events} key={month}/>) | ||
} | ||
</div> | ||
</div> | ||
} | ||
|
||
export default function Timeline() { | ||
// this spread is just because Intl.DateTimeFormat expects a mutable array. | ||
const locale = [...lang.useLocale()]; | ||
|
||
const years = React.useMemo(() => groupBy(Immutable.List(Bio.Bio.timeline).map( | ||
event => { | ||
// depending on locale there may be different numbers of months etc. | ||
const month = Intl.DateTimeFormat(locale, { month: 'long' }).format(event.date); | ||
const year = Intl.DateTimeFormat(locale, { year: 'numeric' }).format(event.date); | ||
|
||
return {...event, month, year} | ||
} | ||
).sort((a, b) => +b.date - +a.date), v => v.year).map( | ||
v => groupBy(v, i => i.month) | ||
), [ locale]); | ||
|
||
return <> | ||
{ | ||
[...years].map(([year, months], i) => | ||
<Year year={year} months={months} key={year}/> | ||
) | ||
} | ||
</> | ||
} |
Oops, something went wrong.