Add character release timeline

pull/1/head
Made Baruna 2022-09-06 23:54:17 +07:00
parent 9940e0c10a
commit 9bdf631bce
7 changed files with 298 additions and 2 deletions

View File

@ -106,6 +106,7 @@
'artifacts', 'artifacts',
'radiant-spincrystal', 'radiant-spincrystal',
'calendar', 'calendar',
'banners',
].includes(segment)} ].includes(segment)}
image="/images/items.png" image="/images/items.png"
label={$t('sidebar.database')} label={$t('sidebar.database')}
@ -119,6 +120,7 @@
{ label: $t('sidebar.fishing'), href: '/fishing' }, { label: $t('sidebar.fishing'), href: '/fishing' },
{ label: $t('sidebar.radiantSpincrystal'), href: '/radiant-spincrystal' }, { label: $t('sidebar.radiantSpincrystal'), href: '/radiant-spincrystal' },
{ label: $t('sidebar.calendar'), href: '/calendar' }, { label: $t('sidebar.calendar'), href: '/calendar' },
{ label: $t('sidebar.banners'), href: '/banners' },
]} ]}
/> />
<SidebarItem <SidebarItem

View File

@ -30,6 +30,7 @@ export const banners = {
timezoneDependent: true, timezoneDependent: true,
featured: ['venti'], featured: ['venti'],
featuredRare: ['barbara', 'fischl', 'xiangling'], featuredRare: ['barbara', 'fischl', 'xiangling'],
version: '1.0',
}, },
{ {
name: 'Sparkling Steps', name: 'Sparkling Steps',
@ -40,6 +41,7 @@ export const banners = {
color: '#CA360E', color: '#CA360E',
featured: ['klee'], featured: ['klee'],
featuredRare: ['xingqiu', 'sucrose', 'noelle'], featuredRare: ['xingqiu', 'sucrose', 'noelle'],
version: '1.0',
}, },
{ {
name: 'Farewell of Snezhnaya', name: 'Farewell of Snezhnaya',
@ -51,6 +53,7 @@ export const banners = {
timezoneDependent: true, timezoneDependent: true,
featured: ['tartaglia'], featured: ['tartaglia'],
featuredRare: ['ningguang', 'beidou', 'diona'], featuredRare: ['ningguang', 'beidou', 'diona'],
version: '1.1',
}, },
{ {
name: 'Gentry of Hermitage', name: 'Gentry of Hermitage',
@ -61,6 +64,7 @@ export const banners = {
color: '#D1A55C', color: '#D1A55C',
featured: ['zhongli'], featured: ['zhongli'],
featuredRare: ['xinyan', 'razor', 'chongyun'], featuredRare: ['xinyan', 'razor', 'chongyun'],
version: '1.1',
}, },
{ {
name: 'Secretum Secretorum', name: 'Secretum Secretorum',
@ -72,6 +76,7 @@ export const banners = {
timezoneDependent: true, timezoneDependent: true,
featured: ['albedo'], featured: ['albedo'],
featuredRare: ['fischl', 'bennett', 'sucrose'], featuredRare: ['fischl', 'bennett', 'sucrose'],
version: '1.2',
}, },
{ {
name: 'Adrift in the Harbor', name: 'Adrift in the Harbor',
@ -82,6 +87,7 @@ export const banners = {
color: '#6994DF', color: '#6994DF',
featured: ['ganyu'], featured: ['ganyu'],
featuredRare: ['xingqiu', 'xiangling', 'noelle'], featuredRare: ['xingqiu', 'xiangling', 'noelle'],
version: '1.2',
}, },
{ {
name: 'Invitation to Mundane Life', name: 'Invitation to Mundane Life',
@ -93,6 +99,7 @@ export const banners = {
timezoneDependent: true, timezoneDependent: true,
featured: ['xiao'], featured: ['xiao'],
featuredRare: ['diona', 'xinyan', 'beidou'], featuredRare: ['diona', 'xinyan', 'beidou'],
version: '1.3',
}, },
{ {
name: 'Dance of Lanterns', name: 'Dance of Lanterns',
@ -103,6 +110,7 @@ export const banners = {
color: '#AB6CD7', color: '#AB6CD7',
featured: ['keqing'], featured: ['keqing'],
featuredRare: ['barbara', 'bennett', 'ningguang'], featuredRare: ['barbara', 'bennett', 'ningguang'],
version: '1.3',
}, },
{ {
name: 'Moment of Bloom', name: 'Moment of Bloom',
@ -113,6 +121,7 @@ export const banners = {
color: '#BF5042', color: '#BF5042',
featured: ['hu_tao'], featured: ['hu_tao'],
featuredRare: ['xingqiu', 'xiangling', 'chongyun'], featuredRare: ['xingqiu', 'xiangling', 'chongyun'],
version: '1.3',
}, },
{ {
name: 'Ballad in Goblets', name: 'Ballad in Goblets',
@ -124,6 +133,7 @@ export const banners = {
featured: ['venti'], featured: ['venti'],
featuredRare: ['sucrose', 'razor', 'noelle'], featuredRare: ['sucrose', 'razor', 'noelle'],
timezoneDependent: true, timezoneDependent: true,
version: '1.4',
}, },
{ {
name: 'Farewell of Snezhnaya', name: 'Farewell of Snezhnaya',
@ -134,6 +144,7 @@ export const banners = {
color: '#50A3C0', color: '#50A3C0',
featured: ['tartaglia'], featured: ['tartaglia'],
featuredRare: ['rosaria', 'fischl', 'barbara'], featuredRare: ['rosaria', 'fischl', 'barbara'],
version: '1.4',
}, },
{ {
name: 'Gentry of Hermitage', name: 'Gentry of Hermitage',
@ -145,6 +156,7 @@ export const banners = {
featured: ['zhongli'], featured: ['zhongli'],
featuredRare: ['yanfei', 'noelle', 'diona'], featuredRare: ['yanfei', 'noelle', 'diona'],
timezoneDependent: true, timezoneDependent: true,
version: '1.5',
}, },
{ {
name: 'Born of Ocean Swell', name: 'Born of Ocean Swell',
@ -155,6 +167,7 @@ export const banners = {
color: '#A6D6E0', color: '#A6D6E0',
featured: ['eula'], featured: ['eula'],
featuredRare: ['xingqiu', 'beidou', 'xinyan'], featuredRare: ['xingqiu', 'beidou', 'xinyan'],
version: '1.5',
}, },
{ {
name: 'Sparkling Steps', name: 'Sparkling Steps',
@ -166,6 +179,7 @@ export const banners = {
featured: ['klee'], featured: ['klee'],
featuredRare: ['fischl', 'sucrose', 'barbara'], featuredRare: ['fischl', 'sucrose', 'barbara'],
timezoneDependent: true, timezoneDependent: true,
version: '1.6',
}, },
{ {
name: 'Leaves in the Wind', name: 'Leaves in the Wind',
@ -176,6 +190,7 @@ export const banners = {
color: '#8FFFDE', color: '#8FFFDE',
featured: ['kaedehara_kazuha'], featured: ['kaedehara_kazuha'],
featuredRare: ['bennett', 'razor', 'rosaria'], featuredRare: ['bennett', 'razor', 'rosaria'],
version: '1.6',
}, },
{ {
name: 'The Herons Court', name: 'The Herons Court',
@ -187,6 +202,7 @@ export const banners = {
featured: ['kamisato_ayaka'], featured: ['kamisato_ayaka'],
featuredRare: ['chongyun', 'ningguang', 'yanfei'], featuredRare: ['chongyun', 'ningguang', 'yanfei'],
timezoneDependent: true, timezoneDependent: true,
version: '2.0',
}, },
{ {
name: 'Tapestry of Golden Flames', name: 'Tapestry of Golden Flames',
@ -197,6 +213,7 @@ export const banners = {
color: '#F7D69F', color: '#F7D69F',
featured: ['yoimiya'], featured: ['yoimiya'],
featuredRare: ['sayu', 'diona', 'xinyan'], featuredRare: ['sayu', 'diona', 'xinyan'],
version: '2.0',
}, },
{ {
name: 'Reign of Serenity', name: 'Reign of Serenity',
@ -208,6 +225,7 @@ export const banners = {
featured: ['raiden_shogun'], featured: ['raiden_shogun'],
featuredRare: ['xiangling', 'sucrose', 'kujou_sara'], featuredRare: ['xiangling', 'sucrose', 'kujou_sara'],
timezoneDependent: true, timezoneDependent: true,
version: '2.1',
}, },
{ {
name: 'Drifting Luminescence', name: 'Drifting Luminescence',
@ -218,6 +236,7 @@ export const banners = {
color: '#FF7B69', color: '#FF7B69',
featured: ['sangonomiya_kokomi'], featured: ['sangonomiya_kokomi'],
featuredRare: ['rosaria', 'beidou', 'xingqiu'], featuredRare: ['rosaria', 'beidou', 'xingqiu'],
version: '2.1',
}, },
{ {
name: 'Farewell of Snezhnaya', name: 'Farewell of Snezhnaya',
@ -229,6 +248,7 @@ export const banners = {
featured: ['tartaglia'], featured: ['tartaglia'],
featuredRare: ['ningguang', 'chongyun', 'yanfei'], featuredRare: ['ningguang', 'chongyun', 'yanfei'],
timezoneDependent: true, timezoneDependent: true,
version: '2.2',
}, },
{ {
name: 'Moment of Bloom', name: 'Moment of Bloom',
@ -239,6 +259,7 @@ export const banners = {
color: '#FF7966', color: '#FF7966',
featured: ['hu_tao'], featured: ['hu_tao'],
featuredRare: ['thoma', 'diona', 'sayu'], featuredRare: ['thoma', 'diona', 'sayu'],
version: '2.2',
}, },
{ {
name: 'Secretum Secretorum', name: 'Secretum Secretorum',
@ -250,6 +271,7 @@ export const banners = {
featured: ['albedo', 'eula'], featured: ['albedo', 'eula'],
featuredRare: ['rosaria', 'noelle', 'bennett'], featuredRare: ['rosaria', 'noelle', 'bennett'],
timezoneDependent: true, timezoneDependent: true,
version: '2.3',
}, },
// { // {
// name: 'Born of Ocean Swell', // name: 'Born of Ocean Swell',
@ -261,6 +283,7 @@ export const banners = {
// featured: ['eula'], // featured: ['eula'],
// featuredRare: ['rosaria', 'noelle', 'bennett'], // featuredRare: ['rosaria', 'noelle', 'bennett'],
// timezoneDependent: true, // timezoneDependent: true,
// version: '2.3'
// }, // },
{ {
name: "Oni's Royale", name: "Oni's Royale",
@ -271,6 +294,7 @@ export const banners = {
color: '#FFB455', color: '#FFB455',
featured: ['arataki_itto'], featured: ['arataki_itto'],
featuredRare: ['gorou', 'xiangling', 'barbara'], featuredRare: ['gorou', 'xiangling', 'barbara'],
version: '2.3',
}, },
{ {
name: 'The Transcendent One Returns', name: 'The Transcendent One Returns',
@ -282,6 +306,7 @@ export const banners = {
featured: ['shenhe', 'xiao'], featured: ['shenhe', 'xiao'],
featuredRare: ['yun_jin', 'ningguang', 'chongyun'], featuredRare: ['yun_jin', 'ningguang', 'chongyun'],
timezoneDependent: true, timezoneDependent: true,
version: '2.4',
}, },
// { // {
// name: 'Invitation to Mundane Life', // name: 'Invitation to Mundane Life',
@ -293,6 +318,7 @@ export const banners = {
// featured: ['shenhe', 'xiao'], // featured: ['shenhe', 'xiao'],
// featuredRare: ['yun_jin', 'ningguang', 'chongyun'], // featuredRare: ['yun_jin', 'ningguang', 'chongyun'],
// timezoneDependent: true, // timezoneDependent: true,
// version: '2.4'
// }, // },
{ {
name: 'Gentry of Hermitage', name: 'Gentry of Hermitage',
@ -303,6 +329,7 @@ export const banners = {
color: '#FFF5BF', color: '#FFF5BF',
featured: ['zhongli', 'ganyu'], featured: ['zhongli', 'ganyu'],
featuredRare: ['xingqiu', 'beidou', 'yanfei'], featuredRare: ['xingqiu', 'beidou', 'yanfei'],
version: '2.4',
}, },
// { // {
// name: 'Adrift in the Harbor', // name: 'Adrift in the Harbor',
@ -324,6 +351,7 @@ export const banners = {
featured: ['yae_miko'], featured: ['yae_miko'],
featuredRare: ['thoma', 'diona', 'fischl'], featuredRare: ['thoma', 'diona', 'fischl'],
timezoneDependent: true, timezoneDependent: true,
version: '2.5',
}, },
{ {
name: 'Reign of Serenity', name: 'Reign of Serenity',
@ -334,6 +362,7 @@ export const banners = {
color: '#D0AEF2', color: '#D0AEF2',
featured: ['raiden_shogun', 'sangonomiya_kokomi'], featured: ['raiden_shogun', 'sangonomiya_kokomi'],
featuredRare: ['bennett', 'xinyan', 'kujou_sara'], featuredRare: ['bennett', 'xinyan', 'kujou_sara'],
version: '2.5',
}, },
// { // {
// name: 'Drifting Luminescence', // name: 'Drifting Luminescence',
@ -344,6 +373,7 @@ export const banners = {
// color: '#53caf3', // color: '#53caf3',
// featured: ['raiden_shogun', 'sangonomiya_kokomi'], // featured: ['raiden_shogun', 'sangonomiya_kokomi'],
// featuredRare: ['bennett', 'xinyan', 'kujou_sara'], // featuredRare: ['bennett', 'xinyan', 'kujou_sara'],
// version: '2.5'
// }, // },
{ {
name: 'Azure Excursion', name: 'Azure Excursion',
@ -355,6 +385,7 @@ export const banners = {
featured: ['kamisato_ayato', 'venti'], featured: ['kamisato_ayato', 'venti'],
featuredRare: ['yun_jin', 'xiangling', 'sucrose'], featuredRare: ['yun_jin', 'xiangling', 'sucrose'],
timezoneDependent: true, timezoneDependent: true,
version: '2.6',
}, },
// { // {
// name: 'Ballad in Goblets', // name: 'Ballad in Goblets',
@ -366,6 +397,7 @@ export const banners = {
// featured: ['kamisato_ayato', 'venti'], // featured: ['kamisato_ayato', 'venti'],
// featuredRare: ['yun_jin', 'xiangling', 'sucrose'], // featuredRare: ['yun_jin', 'xiangling', 'sucrose'],
// timezoneDependent: true, // timezoneDependent: true,
// version: '2.6'
// }, // },
{ {
name: 'The Herons Court', name: 'The Herons Court',
@ -377,6 +409,7 @@ export const banners = {
featured: ['kamisato_ayaka'], featured: ['kamisato_ayaka'],
featuredRare: ['sayu', 'razor', 'rosaria'], featuredRare: ['sayu', 'razor', 'rosaria'],
timezoneDependentEnd: true, timezoneDependentEnd: true,
version: '2.6',
}, },
{ {
name: 'Discerner of Enigmas', name: 'Discerner of Enigmas',
@ -388,6 +421,7 @@ export const banners = {
featured: ['yelan', 'xiao'], featured: ['yelan', 'xiao'],
featuredRare: ['barbara', 'noelle', 'yanfei'], featuredRare: ['barbara', 'noelle', 'yanfei'],
timezoneDependent: true, timezoneDependent: true,
version: '2.7',
}, },
// { // {
// name: 'Invitation to Mundane Life', // name: 'Invitation to Mundane Life',
@ -409,6 +443,7 @@ export const banners = {
color: '#FFB455', color: '#FFB455',
featured: ['arataki_itto'], featured: ['arataki_itto'],
featuredRare: ['chongyun', 'gorou', 'kuki_shinobu'], featuredRare: ['chongyun', 'gorou', 'kuki_shinobu'],
version: '2.7',
}, },
{ {
name: 'Leaves in the Wind', name: 'Leaves in the Wind',
@ -420,6 +455,7 @@ export const banners = {
featured: ['kaedehara_kazuha', 'klee'], featured: ['kaedehara_kazuha', 'klee'],
featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'], featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'],
timezoneDependent: true, timezoneDependent: true,
version: '2.8',
}, },
// { // {
// name: "Sparkling Steps", // name: "Sparkling Steps",
@ -431,6 +467,7 @@ export const banners = {
// featured: ['kaedehara_kazuha', 'klee'], // featured: ['kaedehara_kazuha', 'klee'],
// featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'], // featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'],
// timezoneDependent: true, // timezoneDependent: true,
// version: '2.8'
// }, // },
{ {
name: 'Tapestry of Golden Flames', name: 'Tapestry of Golden Flames',
@ -441,6 +478,7 @@ export const banners = {
color: '#fc8976', color: '#fc8976',
featured: ['yoimiya'], featured: ['yoimiya'],
featuredRare: ['yun_jin', 'xinyan', 'bennett'], featuredRare: ['yun_jin', 'xinyan', 'bennett'],
version: '2.8',
}, },
{ {
name: 'Viridescent Vigil', name: 'Viridescent Vigil',
@ -452,6 +490,7 @@ export const banners = {
featured: ['tighnari', 'zhongli'], featured: ['tighnari', 'zhongli'],
featuredRare: ['collei', 'fischl', 'diona'], featuredRare: ['collei', 'fischl', 'diona'],
timezoneDependent: true, timezoneDependent: true,
version: '3.0',
}, },
// { // {
// name: 'Gentry of Hermitage', // name: 'Gentry of Hermitage',
@ -463,6 +502,7 @@ export const banners = {
// featured: ['tighnari', 'zhongli'], // featured: ['tighnari', 'zhongli'],
// featuredRare: ['collei', 'fischl', 'diona'], // featuredRare: ['collei', 'fischl', 'diona'],
// timezoneDependent: true, // timezoneDependent: true,
// version: '3.0'
// }, // },
], ],
weapons: [ weapons: [

View File

@ -10,6 +10,7 @@ export const bannersDual = {
featured: ['albedo', 'eula'], featured: ['albedo', 'eula'],
featuredRare: ['rosaria', 'noelle', 'bennett'], featuredRare: ['rosaria', 'noelle', 'bennett'],
timezoneDependent: true, timezoneDependent: true,
version: '2.3',
}, },
{ {
name: 'Born of Ocean Swell', name: 'Born of Ocean Swell',
@ -21,6 +22,7 @@ export const bannersDual = {
featured: ['albedo', 'eula'], featured: ['albedo', 'eula'],
featuredRare: ['rosaria', 'noelle', 'bennett'], featuredRare: ['rosaria', 'noelle', 'bennett'],
timezoneDependent: true, timezoneDependent: true,
version: '2.3',
}, },
], ],
'The Transcendent One Returns 1': [ 'The Transcendent One Returns 1': [
@ -34,6 +36,7 @@ export const bannersDual = {
featured: ['shenhe', 'xiao'], featured: ['shenhe', 'xiao'],
featuredRare: ['yun_jin', 'ningguang', 'chongyun'], featuredRare: ['yun_jin', 'ningguang', 'chongyun'],
timezoneDependent: true, timezoneDependent: true,
version: '2.4',
}, },
{ {
name: 'Invitation to Mundane Life', name: 'Invitation to Mundane Life',
@ -45,6 +48,7 @@ export const bannersDual = {
featured: ['shenhe', 'xiao'], featured: ['shenhe', 'xiao'],
featuredRare: ['yun_jin', 'ningguang', 'chongyun'], featuredRare: ['yun_jin', 'ningguang', 'chongyun'],
timezoneDependent: true, timezoneDependent: true,
version: '2.4',
}, },
], ],
'Gentry of Hermitage 3': [ 'Gentry of Hermitage 3': [
@ -57,6 +61,7 @@ export const bannersDual = {
color: '#FFF5BF', color: '#FFF5BF',
featured: ['zhongli', 'ganyu'], featured: ['zhongli', 'ganyu'],
featuredRare: ['xingqiu', 'beidou', 'yanfei'], featuredRare: ['xingqiu', 'beidou', 'yanfei'],
version: '2.4',
}, },
{ {
name: 'Adrift in the Harbor', name: 'Adrift in the Harbor',
@ -67,6 +72,7 @@ export const bannersDual = {
color: '#FFF5BF', color: '#FFF5BF',
featured: ['zhongli', 'ganyu'], featured: ['zhongli', 'ganyu'],
featuredRare: ['xingqiu', 'beidou', 'yanfei'], featuredRare: ['xingqiu', 'beidou', 'yanfei'],
version: '2.4',
}, },
], ],
'Reign of Serenity 2': [ 'Reign of Serenity 2': [
@ -79,6 +85,7 @@ export const bannersDual = {
color: '#D0AEF2', color: '#D0AEF2',
featured: ['raiden_shogun', 'sangonomiya_kokomi'], featured: ['raiden_shogun', 'sangonomiya_kokomi'],
featuredRare: ['bennett', 'xinyan', 'kujou_sara'], featuredRare: ['bennett', 'xinyan', 'kujou_sara'],
version: '2.5',
}, },
{ {
name: 'Drifting Luminescence', name: 'Drifting Luminescence',
@ -89,6 +96,7 @@ export const bannersDual = {
color: '#53caf3', color: '#53caf3',
featured: ['raiden_shogun', 'sangonomiya_kokomi'], featured: ['raiden_shogun', 'sangonomiya_kokomi'],
featuredRare: ['bennett', 'xinyan', 'kujou_sara'], featuredRare: ['bennett', 'xinyan', 'kujou_sara'],
version: '2.5',
}, },
], ],
'Azure Excursion 1': [ 'Azure Excursion 1': [
@ -102,6 +110,7 @@ export const bannersDual = {
featured: ['kamisato_ayato', 'venti'], featured: ['kamisato_ayato', 'venti'],
featuredRare: ['yun_jin', 'xiangling', 'sucrose'], featuredRare: ['yun_jin', 'xiangling', 'sucrose'],
timezoneDependent: true, timezoneDependent: true,
version: '2.6',
}, },
{ {
name: 'Ballad in Goblets', name: 'Ballad in Goblets',
@ -113,6 +122,7 @@ export const bannersDual = {
featured: ['kamisato_ayato', 'venti'], featured: ['kamisato_ayato', 'venti'],
featuredRare: ['yun_jin', 'xiangling', 'sucrose'], featuredRare: ['yun_jin', 'xiangling', 'sucrose'],
timezoneDependent: true, timezoneDependent: true,
version: '2.6',
}, },
], ],
'Discerner of Enigmas 1': [ 'Discerner of Enigmas 1': [
@ -126,6 +136,7 @@ export const bannersDual = {
featured: ['yelan', 'xiao'], featured: ['yelan', 'xiao'],
featuredRare: ['barbara', 'noelle', 'yanfei'], featuredRare: ['barbara', 'noelle', 'yanfei'],
timezoneDependent: true, timezoneDependent: true,
version: '2.7',
}, },
{ {
name: 'Invitation to Mundane Life', name: 'Invitation to Mundane Life',
@ -137,6 +148,7 @@ export const bannersDual = {
featured: ['yelan', 'xiao'], featured: ['yelan', 'xiao'],
featuredRare: ['barbara', 'noelle', 'yanfei'], featuredRare: ['barbara', 'noelle', 'yanfei'],
timezoneDependent: true, timezoneDependent: true,
version: '2.7',
}, },
], ],
'Leaves in the Wind 2': [ 'Leaves in the Wind 2': [
@ -150,6 +162,7 @@ export const bannersDual = {
featured: ['kaedehara_kazuha', 'klee'], featured: ['kaedehara_kazuha', 'klee'],
featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'], featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'],
timezoneDependent: true, timezoneDependent: true,
version: '2.8',
}, },
{ {
name: 'Sparkling Steps', name: 'Sparkling Steps',
@ -161,6 +174,7 @@ export const bannersDual = {
featured: ['kaedehara_kazuha', 'klee'], featured: ['kaedehara_kazuha', 'klee'],
featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'], featuredRare: ['ningguang', 'thoma', 'shikanoin_heizou'],
timezoneDependent: true, timezoneDependent: true,
version: '2.8',
}, },
], ],
'Viridescent Vigil 1': [ 'Viridescent Vigil 1': [
@ -174,6 +188,7 @@ export const bannersDual = {
featured: ['tighnari', 'zhongli'], featured: ['tighnari', 'zhongli'],
featuredRare: ['collei', 'fischl', 'diona'], featuredRare: ['collei', 'fischl', 'diona'],
timezoneDependent: true, timezoneDependent: true,
version: '3.0',
}, },
{ {
name: 'Gentry of Hermitage', name: 'Gentry of Hermitage',
@ -185,6 +200,7 @@ export const bannersDual = {
featured: ['tighnari', 'zhongli'], featured: ['tighnari', 'zhongli'],
featuredRare: ['collei', 'fischl', 'diona'], featuredRare: ['collei', 'fischl', 'diona'],
timezoneDependent: true, timezoneDependent: true,
version: '3.0',
}, },
], ],
}; };

View File

@ -16,6 +16,7 @@
"fishing": "Fishing", "fishing": "Fishing",
"radiantSpincrystal": "Radiant Spincrystal", "radiantSpincrystal": "Radiant Spincrystal",
"calendar": "Calendar", "calendar": "Calendar",
"banners": "Character Reruns",
"settings": "Settings", "settings": "Settings",
"donate": "Donate" "donate": "Donate"
}, },
@ -976,6 +977,10 @@
"lastAppearance": "Last Banner Appearance", "lastAppearance": "Last Banner Appearance",
"lastAppearanceDesc": "When is the character's last appearance on a limited banner", "lastAppearanceDesc": "When is the character's last appearance on a limited banner",
"bannerHover": "X Banner Ago", "bannerHover": "X Banner Ago",
"birthday": "Birthday" "birthday": "Birthday",
"sortByTime": "Sorted by first release",
"sortByRerun": "Sorted by oldest re-run",
"bannerTitle": "Character Release Timeline",
"bannerSubtitle": "See when the character is released and their last re-run"
} }
} }

View File

@ -0,0 +1,229 @@
<script>
import { onMount, tick } from 'svelte';
import { t } from 'svelte-i18n';
import { banners } from '../../data/banners';
import { characters } from '../../data/characters';
import Button from '../../components/Button.svelte';
import Icon from '../../components/Icon.svelte';
import { mdiSwapVertical } from '@mdi/js';
import Ad from '../../components/Ad.svelte';
let container;
let length = 0;
let versions = [];
let rows = [[]];
let names = [{ name: '', length: 0 }];
let hovered = -1;
let __rows5;
let __rows4;
let __names5;
let __names4;
let sort = false;
async function process() {
length = banners.characters.length;
let _versions = {};
let _chars5 = {};
let _chars4 = {};
let _rows5 = [];
let _rows4 = [];
let _names5 = [];
let _names4 = [];
let pos5 = 0;
let pos4 = 0;
let len = 0;
for (const banner of banners.characters) {
if (_versions[banner.version] === undefined) {
_versions[banner.version] = 0;
}
_versions[banner.version]++;
for (const ch of Object.keys(_chars5)) {
_chars5[ch].length++;
_names5[_chars5[ch].pos].length++;
_rows5[_chars5[ch].pos][len] = { l: _chars5[ch].length, m: 15 };
}
for (const ch of Object.keys(_chars4)) {
_chars4[ch].length++;
_names4[_chars4[ch].pos].length++;
_rows4[_chars4[ch].pos][len] = { l: _chars4[ch].length, m: 9 };
}
for (const char of banner.featured) {
if (_chars5[char] === undefined) {
_chars5[char] = {
pos: pos5,
length: 0,
};
_names5[pos5] = { name: characters[char].name, length: 0 };
_rows5[pos5] = [...new Array(len).fill({ l: '' }), { char, l: 0 }];
pos5++;
} else {
_rows5[_chars5[char].pos][len] = { char, l: 0 };
_names5[_chars5[char].pos].length = 0;
_chars5[char].length = 0;
}
}
for (const char of banner.featuredRare) {
if (_chars4[char] === undefined) {
_chars4[char] = {
pos: pos4,
length: 0,
};
_names4[pos4] = { name: characters[char].name, length: 0 };
_rows4[pos4] = [...new Array(len).fill({ l: '' }), { char, l: 0 }];
pos4++;
} else {
_rows4[_chars4[char].pos][len] = { char, l: 0 };
_names4[_chars4[char].pos].length = 0;
_chars4[char].length = 0;
}
}
len++;
}
versions = Object.entries(_versions).map(([version, length]) => ({
version,
length,
}));
__rows5 = _rows5;
__rows4 = _rows4;
__names5 = _names5;
__names4 = _names4;
rows = [..._rows5, new Array(length).fill({ l: '' }), ..._rows4];
names = [..._names5, { name: '', length: 0 }, ..._names4];
await tick();
container.scrollTo({
left: container.scrollWidth,
top: 0,
behavior: 'smooth',
});
}
function sortOrder() {
sort = !sort;
if (!sort) {
rows = [...__rows5, new Array(length).fill({ l: '' }), ...__rows4];
names = [...__names5, { name: '', length: 0 }, ...__names4];
return;
}
const _rows5 = [...__rows5].sort((a, b) => b[length - 1].l - a[length - 1].l);
const _rows4 = [...__rows4].sort((a, b) => b[length - 1].l - a[length - 1].l);
const _names5 = [...__names5].sort((a, b) => b.length - a.length);
const _names4 = [...__names4].sort((a, b) => b.length - a.length);
console.log(_rows5);
rows = [..._rows5, new Array(length).fill({ l: '' }), ..._rows4];
names = [..._names5, { name: '', length: 0 }, ..._names4];
}
function getColor(index, max) {
if (index === '') return 'none';
const hue = ((max - index) / max) * 100;
return `hsl(${hue}, 60%, 70%)`;
}
function onHover(index) {
hovered = index;
}
onMount(() => {
process();
});
</script>
<svelte:head>
<title>Character Release Timeline - Paimon.moe</title>
<meta name="description" content="Genshin Impact Character Release Timeline" />
<meta property="og:description" content="See when the character is released and their last re-run" />
</svelte:head>
<div class="lg:ml-64 pt-20 lg:pt-8">
<div class="mb-4 pl-8">
<h1 class="font-display font-black text-2xl xl:text-5xl mb-3 xl:mb-0 text-white">{$t('calendar.bannerTitle')}</h1>
<p class="text-gray-400 font-medium pb-4 leading-none" style="margin-top: -1rem;">
{$t('calendar.bannerSubtitle')}
</p>
<div class="flex">
<p class="text-white mr-2 border-2 border-white border-opacity-25 px-4 py-2 rounded-xl">
{$t(sort ? 'calendar.sortByRerun' : 'calendar.sortByTime')}
</p>
<Button size="sm" className="px-2" on:click={sortOrder}><Icon path={mdiSwapVertical} /></Button>
</div>
</div>
<div class="overflow-x-auto whitespace-nowrap px-8 pb-4" bind:this={container}>
<table class="table-fixed">
<tbody>
<tr>
{#each versions as v, index}
<td class="text-center border border-gray-600 text-white font-bold relative" colspan={v.length}
>{v.version}</td
>
{/each}
</tr>
{#each rows as r, rowIndex}
<tr>
{#each r as col, index}
{#if col.char}
<td on:mouseenter={() => onHover(index)} class="cell {hovered === index ? 'hovered' : ''}">
<img class="w-full h-full" src="/images/characters/{col.char}.png" alt={col.char} />
</td>
{:else}
<td
on:mouseenter={() => onHover(index)}
class="cell {hovered === index ? 'hovered' : ''}"
style="background: {getColor(col.l, col.m)};">{col.l}</td
>
{/if}
{/each}
<td class="border border-gray-600 text-white px-2">{$t(names[rowIndex].name)}</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
<Ad type="desktop" variant="lb" id="2" />
<Ad type="mobile" variant="lb" id="1" />
<style lang="postcss">
.cell {
@apply border border-gray-600 w-8 h-8 min-w-[2rem] min-h-[2rem] xl:min-w-[2.5rem] xl:min-h-[2.5rem] xl:w-10 xl:h-10 text-center relative z-0;
}
.hovered::after {
content: '';
@apply absolute bg-white bg-opacity-20 left-0 top-0 h-8 w-8 xl:h-10 xl:w-10;
}
::-webkit-scrollbar {
height: 8px;
}
::-webkit-scrollbar-track {
@apply bg-transparent;
margin: 0 20px;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.35);
@apply rounded-xl;
}
</style>

View File

@ -27,6 +27,7 @@
import { getAccountPrefix } from '../../stores/account'; import { getAccountPrefix } from '../../stores/account';
import { readSave } from '../../stores/saveManager'; import { readSave } from '../../stores/saveManager';
import { bannersDual } from '../../data/bannersDual'; import { bannersDual } from '../../data/bannersDual';
import Ad from '../../components/Ad.svelte';
const { open: openModal } = getContext('simple-modal'); const { open: openModal } = getContext('simple-modal');
@ -527,6 +528,8 @@
</div> </div>
</div> </div>
</div> </div>
<Ad type="desktop" variant="lb" id="2" />
<Ad type="mobile" variant="lb" id="1" />
<style lang="postcss"> <style lang="postcss">
.event-strip { .event-strip {

View File

@ -8,10 +8,11 @@ const IMAGE_CACHE = `cacheimg${IMAGE_CACHE_VER}`;
const IMAGE_URL = `${self.location.origin}/images/`; const IMAGE_URL = `${self.location.origin}/images/`;
const changelog = [ const changelog = [
'Add character release timeline (Database > Character Reruns)',
'Add checklist to achievement', 'Add checklist to achievement',
'Update achievement commission list', 'Update achievement commission list',
'Update wish import instruction for pc', 'Update wish import instruction for pc',
'Adjust calendar view on mobile', 'Update timeline',
]; ];
const channel = new BroadcastChannel('paimonmoe-sw'); const channel = new BroadcastChannel('paimonmoe-sw');