mirror of
https://github.com/MadeBaruna/paimon-moe.git
synced 2025-03-26 00:17:06 +01:00
Show timeline as local time
This commit is contained in:
parent
c1991992ae
commit
467038023c
4 changed files with 169 additions and 131 deletions
src
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import dayjs from 'dayjs';
|
||||
import { onMount } from 'svelte';
|
||||
import { getCurrentTime } from '../../stores/server';
|
||||
|
||||
export let event;
|
||||
|
||||
|
@ -9,7 +8,7 @@
|
|||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
now = getCurrentTime();
|
||||
now = dayjs();
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
|
|
|
@ -41,13 +41,13 @@
|
|||
{event.name}
|
||||
</span>
|
||||
{#if started && !ended && !event.startOnly}
|
||||
<div class="absolute pl-3" style="top: 6px; right: -200px; width: 200px;">
|
||||
<div class="absolute pl-3" style="top: 6px; right: -120px; width: 120px;">
|
||||
<span class="text-sm rounded-xl text-black font-semibold bg-white bg-opacity-75 px-1">
|
||||
{dayjs.duration(diffEnd).format(diffEnd > 86400000 ? 'D[d] HH:mm:ss' : 'HH:mm:ss')}
|
||||
</span>
|
||||
</div>
|
||||
{:else if !started && !ended}
|
||||
<div class="absolute pr-3 text-right" style="top: 6px; left: {prevNearby ? '-150px' : '-200px'}; width: 200px;">
|
||||
<div class="absolute pr-3 text-right" style="top: 6px; left: {prevNearby ? '-80px' : '-120px'}; width: 120px;">
|
||||
<span class="text-sm rounded-xl text-black font-semibold bg-white bg-opacity-75 px-1">
|
||||
{dayjs.duration(diffStart).format(diffStart > 86400000 ? 'D[d] HH:mm:ss' : 'HH:mm:ss')}
|
||||
</span>
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
import duration from 'dayjs/plugin/duration';
|
||||
dayjs.extend(duration);
|
||||
|
||||
import { getCurrentTime } from '../../stores/server';
|
||||
import { getTimeDifference } from '../../stores/server';
|
||||
import { eventsData } from '../../data/timeline';
|
||||
|
||||
import Checkbox from '../../components/Checkbox.svelte';
|
||||
import EventItem from './_item.svelte';
|
||||
import DetailModal from './_detail.svelte';
|
||||
|
||||
|
@ -25,8 +26,14 @@
|
|||
);
|
||||
}
|
||||
|
||||
let loading = true;
|
||||
|
||||
let timelineContainer;
|
||||
|
||||
let showAsLocalTime = true;
|
||||
let timeDifference = 0;
|
||||
let timeDifferenceEvent = 0;
|
||||
|
||||
let dayWidth = 50;
|
||||
const eventHeight = 36;
|
||||
const eventMargin = 20;
|
||||
|
@ -34,13 +41,16 @@
|
|||
const marginTop = 80;
|
||||
|
||||
let lastEventTime = dayjs().year(2000);
|
||||
let firstDay;
|
||||
let firstDay = dayjs();
|
||||
let dates = [];
|
||||
let months = {};
|
||||
let monthList = [];
|
||||
let events = [];
|
||||
let today = dayjs();
|
||||
|
||||
function convertToDate(e, i) {
|
||||
const start = dayjs(e.start, 'YYYY-MM-DD HH:mm:ss');
|
||||
const end = dayjs(e.end, 'YYYY-MM-DD HH:mm:ss');
|
||||
const start = dayjs(e.start, 'YYYY-MM-DD HH:mm:ss').subtract(timeDifferenceEvent, 'minute');
|
||||
const end = dayjs(e.end, 'YYYY-MM-DD HH:mm:ss').subtract(timeDifferenceEvent, 'minute');
|
||||
const duration = end.diff(start, 'day', true);
|
||||
|
||||
if (lastEventTime < end) lastEventTime = end;
|
||||
|
@ -54,79 +64,93 @@
|
|||
};
|
||||
}
|
||||
|
||||
let events = eventsData.map((e, i) => {
|
||||
if (Array.isArray(e)) {
|
||||
return e.map((item) => convertToDate(item, i));
|
||||
}
|
||||
|
||||
return convertToDate(e, i);
|
||||
});
|
||||
|
||||
events
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
if (Array.isArray(a) && Array.isArray(b)) {
|
||||
return a[0].start - b[0].start;
|
||||
} else if (!Array.isArray(a) && Array.isArray(b)) {
|
||||
return a.start - b[0].start;
|
||||
} else if (Array.isArray(a) && !Array.isArray(b)) {
|
||||
return a[0].start - b.start;
|
||||
} else {
|
||||
return a.start - b.start;
|
||||
}
|
||||
})
|
||||
.forEach((e, i) => {
|
||||
if (i === 0) {
|
||||
if (Array.isArray(e)) {
|
||||
firstDay = e[0].start.set('hour', 0).set('minute', 0).set('second', 0).subtract(padding, 'day');
|
||||
} else {
|
||||
firstDay = e.start.set('hour', 0).set('minute', 0).set('second', 0).subtract(padding, 'day');
|
||||
}
|
||||
}
|
||||
|
||||
function processEvent() {
|
||||
events = eventsData.map((e, i) => {
|
||||
if (Array.isArray(e)) {
|
||||
for (let j = 0; j < e.length; j++) {
|
||||
const current = e[j];
|
||||
|
||||
const offset = Math.abs(firstDay.diff(events[current.index][j].start, 'day', true));
|
||||
events[current.index][j].offset = offset;
|
||||
}
|
||||
} else {
|
||||
const offset = Math.abs(firstDay.diff(e.start, 'day', true));
|
||||
events[e.index].offset = offset;
|
||||
return e.map((item) => convertToDate(item, i));
|
||||
}
|
||||
|
||||
return convertToDate(e, i);
|
||||
});
|
||||
|
||||
let today = getCurrentTime();
|
||||
$: todayOffset = Math.abs(firstDay.diff(today, 'day', true));
|
||||
events
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
if (Array.isArray(a) && Array.isArray(b)) {
|
||||
return a[0].start - b[0].start;
|
||||
} else if (!Array.isArray(a) && Array.isArray(b)) {
|
||||
return a.start - b[0].start;
|
||||
} else if (Array.isArray(a) && !Array.isArray(b)) {
|
||||
return a[0].start - b.start;
|
||||
} else {
|
||||
return a.start - b.start;
|
||||
}
|
||||
})
|
||||
.forEach((e, i) => {
|
||||
if (i === 0) {
|
||||
if (Array.isArray(e)) {
|
||||
firstDay = e[0].start.set('hour', 0).set('minute', 0).set('second', 0).subtract(padding, 'day');
|
||||
} else {
|
||||
firstDay = e.start.set('hour', 0).set('minute', 0).set('second', 0).subtract(padding, 'day');
|
||||
}
|
||||
}
|
||||
|
||||
const dayTotal = Math.abs(Math.ceil(firstDay.diff(lastEventTime, 'day', true))) + 2 * padding;
|
||||
if (Array.isArray(e)) {
|
||||
for (let j = 0; j < e.length; j++) {
|
||||
const current = e[j];
|
||||
|
||||
for (let i = 0; i < dayTotal; i++) {
|
||||
const month = firstDay.add(i, 'day').format('MMMM');
|
||||
if (months[month] === undefined) {
|
||||
months[month] = {
|
||||
total: 0,
|
||||
offset: 0,
|
||||
};
|
||||
const offset = Math.abs(firstDay.diff(events[current.index][j].start, 'day', true));
|
||||
events[current.index][j].offset = offset;
|
||||
}
|
||||
} else {
|
||||
const offset = Math.abs(firstDay.diff(e.start, 'day', true));
|
||||
events[e.index].offset = offset;
|
||||
}
|
||||
});
|
||||
|
||||
const dayTotal = Math.abs(Math.ceil(firstDay.diff(lastEventTime, 'day', true))) + 2 * padding;
|
||||
|
||||
months = [];
|
||||
for (let i = 0; i < dayTotal; i++) {
|
||||
const month = firstDay.add(i, 'day').format('MMMM');
|
||||
if (months[month] === undefined) {
|
||||
months[month] = {
|
||||
total: 0,
|
||||
offset: 0,
|
||||
};
|
||||
}
|
||||
|
||||
months[month].total++;
|
||||
}
|
||||
|
||||
months[month].total++;
|
||||
monthList = Object.entries(months);
|
||||
for (let i = 0; i < monthList.length; i++) {
|
||||
monthList[i][1].offset = i - 1 >= 0 ? monthList[i - 1][1].total + monthList[i - 1][1].offset : 0;
|
||||
}
|
||||
|
||||
dates = [...new Array(dayTotal)].map((_, i) => firstDay.add(i, 'day').date());
|
||||
}
|
||||
|
||||
const monthList = Object.entries(months);
|
||||
for (let i = 0; i < monthList.length; i++) {
|
||||
monthList[i][1].offset = i - 1 >= 0 ? monthList[i - 1][1].total + monthList[i - 1][1].offset : 0;
|
||||
}
|
||||
async function toggleLocalTime() {
|
||||
const diff = getTimeDifference();
|
||||
|
||||
dates = [...new Array(dayTotal)].map((_, i) => firstDay.add(i, 'day').date());
|
||||
if (showAsLocalTime) {
|
||||
timeDifferenceEvent = diff;
|
||||
timeDifference = 0;
|
||||
} else {
|
||||
timeDifferenceEvent = 0;
|
||||
timeDifference = diff;
|
||||
}
|
||||
|
||||
today = dayjs().add(timeDifference, 'minute');
|
||||
await tick();
|
||||
processEvent();
|
||||
loading = false;
|
||||
await tick();
|
||||
|
||||
onMount(() => {
|
||||
console.log(firstDay);
|
||||
console.log(events);
|
||||
if (timelineContainer.offsetWidth < 500) {
|
||||
dayWidth = 40;
|
||||
tick();
|
||||
await tick();
|
||||
}
|
||||
|
||||
timelineContainer.scrollTo({
|
||||
|
@ -134,9 +158,13 @@
|
|||
top: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await toggleLocalTime();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
today = getCurrentTime();
|
||||
today = dayjs().add(timeDifference, 'minute');
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
|
@ -151,6 +179,9 @@
|
|||
|
||||
event.currentTarget.scrollLeft += event.deltaY;
|
||||
}
|
||||
|
||||
$: todayOffset = Math.abs(firstDay.diff(today, 'day', true));
|
||||
$: showAsLocalTime, toggleLocalTime();
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -167,80 +198,85 @@
|
|||
|
||||
<div class="lg:ml-64 pt-20 lg:pt-8">
|
||||
<h1 class="font-display px-4 md:px-8 font-black text-5xl text-white">Timeline</h1>
|
||||
<div class="w-full overflow-x-auto px-4 md:px-8" bind:this={timelineContainer} on:mousewheel={transformScroll}>
|
||||
<div
|
||||
style={`padding-top: 50px; width: min-content; padding-right: ${2 * padding * dayWidth}px; height: ${
|
||||
marginTop + events.length * (eventHeight + eventMargin)
|
||||
}px`}
|
||||
class="timeline flex flex-col relative content"
|
||||
>
|
||||
<!-- DATE BAR -->
|
||||
{#each dates as date, i}
|
||||
<div
|
||||
class="bg-gray-700"
|
||||
style={`width: 1px; height: calc(100% - ${eventHeight}px); position: absolute;
|
||||
{#if !loading}
|
||||
<div class="px-4 md:px-8 text-white select-none">
|
||||
<Checkbox bind:checked={showAsLocalTime}>Show as local time</Checkbox>
|
||||
</div>
|
||||
<div class="w-full overflow-x-auto px-4 md:px-8" bind:this={timelineContainer} on:mousewheel={transformScroll}>
|
||||
<div
|
||||
style={`padding-top: 50px; width: min-content; padding-right: ${2 * padding * dayWidth}px; height: ${
|
||||
marginTop + events.length * (eventHeight + eventMargin)
|
||||
}px`}
|
||||
class="timeline flex flex-col relative content"
|
||||
>
|
||||
<!-- DATE BAR -->
|
||||
{#each dates as date, i}
|
||||
<div
|
||||
class="bg-gray-700"
|
||||
style={`width: 1px; height: calc(100% - ${eventHeight}px); position: absolute;
|
||||
left: ${i * dayWidth}px; top: ${eventHeight}px;`}
|
||||
>
|
||||
<span
|
||||
class="absolute top-0 text-gray-200 text-center pb-1 bg-background-secondary"
|
||||
style="width: 20px; left: -10px;"
|
||||
>
|
||||
{date}
|
||||
</span>
|
||||
</div>
|
||||
{/each}
|
||||
<!-- MONTH TITLE -->
|
||||
{#each monthList as [month, item]}
|
||||
<div
|
||||
class="absolute bg-background-secondary pr-4"
|
||||
style={`top: 12px; width: ${item.total * dayWidth}px; left: ${item.offset * dayWidth}px;`}
|
||||
>
|
||||
<span class="text-legendary-from font-bold sticky left-0">{month}</span>
|
||||
</div>
|
||||
{/each}
|
||||
<!-- EVENT STRIP -->
|
||||
{#each events as event, i}
|
||||
{#if Array.isArray(event)}
|
||||
{#each event as item, j}
|
||||
<span
|
||||
class="absolute top-0 text-gray-200 text-center pb-1 bg-background-secondary"
|
||||
style="width: 20px; left: -10px;"
|
||||
>
|
||||
{date}
|
||||
</span>
|
||||
</div>
|
||||
{/each}
|
||||
<!-- MONTH TITLE -->
|
||||
{#each monthList as [month, item]}
|
||||
<div
|
||||
class="absolute bg-background-secondary pr-4"
|
||||
style={`top: 12px; width: ${item.total * dayWidth}px; left: ${item.offset * dayWidth}px;`}
|
||||
>
|
||||
<span class="text-legendary-from font-bold sticky left-0">{month}</span>
|
||||
</div>
|
||||
{/each}
|
||||
<!-- EVENT STRIP -->
|
||||
{#each events as event, i}
|
||||
{#if Array.isArray(event)}
|
||||
{#each event as item, j}
|
||||
<EventItem
|
||||
prev={j > 0 ? event[j - 1] : null}
|
||||
next={j < event.length - 1 ? event[j + 1] : null}
|
||||
now={today}
|
||||
event={item}
|
||||
openDetail={() => openDetail(item)}
|
||||
{dayWidth}
|
||||
{marginTop}
|
||||
{eventHeight}
|
||||
{eventMargin}
|
||||
{i}
|
||||
/>
|
||||
{/each}
|
||||
{:else}
|
||||
<EventItem
|
||||
prev={j > 0 ? event[j - 1] : null}
|
||||
next={j < event.length - 1 ? event[j + 1] : null}
|
||||
now={today}
|
||||
event={item}
|
||||
openDetail={() => openDetail(item)}
|
||||
openDetail={() => openDetail(event)}
|
||||
{event}
|
||||
{dayWidth}
|
||||
{marginTop}
|
||||
{eventHeight}
|
||||
{eventMargin}
|
||||
{i}
|
||||
/>
|
||||
{/each}
|
||||
{:else}
|
||||
<EventItem
|
||||
now={today}
|
||||
openDetail={() => openDetail(event)}
|
||||
{event}
|
||||
{dayWidth}
|
||||
{marginTop}
|
||||
{eventHeight}
|
||||
{eventMargin}
|
||||
{i}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
<!-- NOW BAR -->
|
||||
<div
|
||||
class="bg-gray-200 z-20 relative opacity-75"
|
||||
style={`left: ${
|
||||
todayOffset * dayWidth
|
||||
}px; width: 2px; height: calc(100% - 10px); position: absolute; top: 10px;`}
|
||||
>
|
||||
<div class="absolute rounded-xl top-0 text-center bg-white text-black" style="width: 80px; left: -40px;">
|
||||
{today.format('HH:mm:ss')}
|
||||
{/if}
|
||||
{/each}
|
||||
<!-- NOW BAR -->
|
||||
<div
|
||||
class="bg-gray-200 z-20 relative opacity-75"
|
||||
style={`left: ${
|
||||
todayOffset * dayWidth
|
||||
}px; width: 2px; height: calc(100% - 10px); position: absolute; top: 10px;`}
|
||||
>
|
||||
<div class="absolute rounded-xl top-0 text-center bg-white text-black" style="width: 80px; left: -40px;">
|
||||
{today.format('HH:mm:ss')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -19,8 +19,11 @@ const timeOffset = {
|
|||
|
||||
const weekdays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
|
||||
|
||||
export const getCurrentTime = () => {
|
||||
return dayjs().utcOffset(timeOffset[get(server)]);
|
||||
export const getTimeDifference = () => {
|
||||
const now = dayjs();
|
||||
const local = now.utcOffset();
|
||||
const serverTime = now.utcOffset(timeOffset[get(server)]).utcOffset();
|
||||
return serverTime - local;
|
||||
}
|
||||
|
||||
export const getCurrentDay = () => {
|
||||
|
|
Loading…
Add table
Reference in a new issue