Skip to content

Commit

Permalink
List previous events
Browse files Browse the repository at this point in the history
  • Loading branch information
dolanske committed Jul 29, 2024
1 parent cac0ae4 commit e84d1d5
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 22 deletions.
37 changes: 32 additions & 5 deletions src/components/Sidebar.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
import { div, h2, hr, img, p } from '@dolanske/cascade'
import { button, div, h2, hr, img, p } from '@dolanske/cascade'
import { type Ref, ref } from '@vue/reactivity'

Check failure on line 2 in src/components/Sidebar.ts

View workflow job for this annotation

GitHub Actions / deploy

'ref' is declared but its value is never read.
import type { FormattedEvent } from '../types'

interface Props {
upcomingCount: number
// pastCount: number
formattedEvents: Ref<FormattedEvent[]>
}

// I don't feel like fixing my libraries rn so I'll do it the old fashioned way
function setActiveHash(e: any) {
const upcoming = document.querySelector('#upcoming')
const past = document.querySelector('#previous')
const id = e.target?.id

if (id === 'upcoming') {
upcoming?.classList.add('active')
past?.classList.remove('active')
}
else if (id === 'previous') {
upcoming?.classList.remove('active')
past?.classList.add('active')
}

window.location.hash = id
}

export const Sidebar = div().setup((ctx, props: Props) => {
ctx.class('sidebar')
ctx.nest([
img().attr('src', 'https://mavulp.github.io/countdown/logo.svg'),
h2('Hivecom \n countdown'),
p(`${props.upcomingCount} upcoming`),
// p(`${props.pastCount} past events`),
p(`${props.formattedEvents.value.length} upcoming`),
hr(),
button('Upcoming Events')
.class({ active: ['#upcoming', ''].includes(window.location.hash) })
.id('upcoming')
.click(setActiveHash),
button('Previous')
.class({ active: window.location.hash === '#previous' })
.id('previous')
.click(setActiveHash),
div().style('flex', 1),
p().html(`Collection of upcoming events in the hivecom community. If you want your event added, please <a href="https://github.com/Mavulp/countdown/issues/new?assignees=dolanske&labels=&projects=&template=new-event.md&title=%5BRequest%5D+New+event" tarrget="_blank">create an issue</a>. <br /><br /> Designed and implemented by dolanske on Wednesday, in 2024.`),
hr(),
Expand Down
23 changes: 23 additions & 0 deletions src/data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createClient } from '@supabase/supabase-js'
import type { Database } from '../types/supabase'
import type { FormattedEvent } from './types'

export const supabase = createClient<Database>(
'https://camqocmuyolpjjbnbcha.supabase.co',
Expand All @@ -10,3 +11,25 @@ export async function getEvents() {
const { data } = await supabase.from('events').select()
return data
}

export const FAKE_EVENT_TITLE = 'fake-event-identifier'

export function createFakeEvent(id: number): FormattedEvent {
return {
created_at: '',
created_by: null,
date: '',
description: '',
id: id + 99999999,
link: null,
location: null,
markdown: null,
modified_at: null,
modified_by: null,
note: null,
title: FAKE_EVENT_TITLE,
displayDate: '',
untilDate: '',
untilTime: '',
}
}
64 changes: 48 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { div, fragment, ul } from '@dolanske/cascade'
import { div, fragment, li, ul } from '@dolanske/cascade'
import { ref } from '@vue/reactivity'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
Expand All @@ -14,29 +14,64 @@ dayjs.extend(relativeTime)
dayjs.extend(customParseFormat)
dayjs.extend(duration)

// Fetch just once on load
const events = await getEvents() ?? []
const formattedEvents = ref<FormattedEvent[]>([])

const formattedEvents = ref<FormattedEvent[]>(formatEventData(
events
.filter(item => dayjs().isBefore(dayjs(item.date, INPUT_FORMAT)))
.sort((a, b) => dayjs(a.date, INPUT_FORMAT).isBefore(dayjs(b.date, INPUT_FORMAT)) ? -1 : 1),
))
// ----------------------------------------------------------------------------
function sortAndFormatDataset() {
switch (window.location.hash) {
case '#previous': {
formattedEvents.value = formatEventData(
events
.filter(item => dayjs().isAfter(dayjs(item.date, INPUT_FORMAT)))
.sort((a, b) => dayjs(a.date, INPUT_FORMAT).isAfter(dayjs(b.date, INPUT_FORMAT)) ? -1 : 1),
)
break
}

case '#upcoming':
default: {
formattedEvents.value = formatEventData(
events
.filter(item => dayjs().isBefore(dayjs(item.date, INPUT_FORMAT)))
.sort((a, b) => dayjs(a.date, INPUT_FORMAT).isBefore(dayjs(b.date, INPUT_FORMAT)) ? -1 : 1),
)
break
}
}
}

// Initially sort dataset
sortAndFormatDataset()

// Watch for hash changes and sort again
window.addEventListener('hashchange', sortAndFormatDataset)

// ----------------------------------------------------------------------------
// Recalculate fillter items when page resizes
let prevSize = 0
window.addEventListener('resize', () => {
// I can't be arsed to optimize this, but at least we won't resize when it's
// not needed on phone & desktop
if (prevSize <= 1280 && prevSize >= 512) {
formattedEvents.value = formatEventData(formattedEvents.value)
}
prevSize = document.documentElement.clientWidth
})

// ----------------------------------------------------------------------------
// One time use component for logic extraction
const Countdown = ul().setup(async (ctx) => {
// Get the square root of the event count, to more evenly distrubute them
// across the viewport
const columns = Math.min(3, Math.ceil(Math.sqrt(events.length)))
ctx.style({ 'grid-template-columns': `repeat(${columns}, 1fr)` })

// Update time until all the events every second
const intervalHandler = setInterval(() => {
formattedEvents.value = formatEventData(formattedEvents.value)
}, 1000)

// Render items
ctx.for(formattedEvents, (event) => {
if (event.title === 'fake-event-identifier')
return li('').class('filler')

return CountdownItem().props(event)
})

Expand All @@ -47,10 +82,7 @@ const Countdown = ul().setup(async (ctx) => {
const App = fragment([
Countdown,
div(
Sidebar.props({
upcomingCount: formattedEvents.value.length,
// pastCount: events.length - formattedEvents.value.length,
}),
Sidebar.props({ formattedEvents }),
).class('sidebar-wrap'),
])

Expand Down
30 changes: 30 additions & 0 deletions src/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ html {
display: flex;

* {
font-family: 'Inter';
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
Expand Down Expand Up @@ -93,6 +94,34 @@ html {
}
}
}

button {
height: 40px;
width: calc(100% + 32px);
text-align: left;
padding: 0 16px;
margin-left: -16px;
position: relative;
color: var(--color-text-lighter);

&.active {
color: var(--color-text);

&:before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 2px;
background-color: var(--color-accent);
}
}

&:hover {
background-color: var(--color-bg-light);
}
}
}

ul {
Expand All @@ -101,6 +130,7 @@ html {
height: 100%;
flex: 1;
background-color: var(--color-bg-black);
grid-template-columns: repeat(3, 1fr);

--item-padding: 20px;

Expand Down
23 changes: 22 additions & 1 deletion src/time.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import dayjs from 'dayjs'
import type { EventItem, FormattedEvent } from './types'
import { FAKE_EVENT_TITLE, createFakeEvent } from './data'

// Specify the date input format
export const INPUT_FORMAT = 'YYYY-MM-DD'
Expand All @@ -20,12 +21,32 @@ export function formatDisplayDate(date: string) {
}

export function formatEventData(events: Array<FormattedEvent | EventItem>): FormattedEvent[] {
return events.map((event) => {
events = events.filter(e => e.title !== FAKE_EVENT_TITLE)

const data = events.map((event) => {
return {
...event,
displayDate: formatDisplayDate(event.date),
untilDate: formatDateUntil(event.date),
untilTime: formatTimeUntil(),
}
})

// Pad events to always fill the screen
const clientWidth = document.documentElement.clientWidth

if (clientWidth >= 1280) {
// Desktop, needs a 9x9 grid
for (let i = data.length; i < 9; i++) {
data.push(createFakeEvent(i))
}
}
else if (clientWidth < 1280 && clientWidth >= 888) {
// Tablet, needs 2x6 grid
for (let i = data.length; i < 6; i++) {
data.push(createFakeEvent(i))
}
}

return data
}

0 comments on commit e84d1d5

Please sign in to comment.