Skip to content

Commit bece8fd

Browse files
hollowayNGPixel
andauthored
feat: Agenda URL #hash scrolls to 'now' or specific day (#7772)
* feat: Agenda URL #now scroll to current event * fix: agendaData date offset for dev purposes * feat: scroll to day * fix: Showing correct hostname in agenda modify log * feat: mobile menu scroll to hash and general bug fixes * fix: agenda mobile menu formatting and Playwright selectors * fix: removing spurious ? mark * chore: removing redundant agenda time setter in favour of agenda settings panel for debugging * style: Update AgendaMobileBar.vue * style: Update AgendaScheduleList.vue --------- Co-authored-by: Nicolas Giard <github@ngpixel.com>
1 parent af21347 commit bece8fd

File tree

6 files changed

+85
-19
lines changed

6 files changed

+85
-19
lines changed

client/agenda/Agenda.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ function reconnectScrollObservers () {
434434
scrollObserver.disconnect()
435435
visibleDays.length = 0
436436
for (const mDay of agendaStore.meetingDays) {
437-
const el = document.getElementById(`agenda-day-${mDay.slug}`)
437+
const el = document.getElementById(mDay.slug)
438438
el.dataset.dayId = mDay.slug.toString()
439439
el.dataset.dayTs = mDay.ts
440440
scrollObserver.observe(el)

client/agenda/AgendaMobileBar.vue

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
<script setup>
3131
import { computed, h } from 'vue'
32-
3332
import {
3433
NBadge,
3534
NDropdown,
@@ -51,21 +50,48 @@ const siteStore = useSiteStore()
5150
5251
// Meeting Days
5352
53+
function optionToLink(opts){
54+
const { key, label, icon } = opts
55+
56+
return {
57+
...opts,
58+
type: 'render',
59+
render: () => h(
60+
'a',
61+
{
62+
class: 'dropdown-link',
63+
'data-testid': 'mobile-link',
64+
href: `#${key}`
65+
},
66+
[
67+
h(
68+
'span',
69+
icon()
70+
),
71+
h(
72+
'span',
73+
label
74+
)
75+
]
76+
)
77+
}
78+
}
79+
5480
const jumpToDayOptions = computed(() => {
5581
const days = []
5682
if (agendaStore.isMeetingLive) {
57-
days.push({
83+
days.push(optionToLink({
5884
label: 'Jump to Now',
5985
key: 'now',
6086
icon: () => h('i', { class: 'bi bi-arrow-down-right-square text-red' })
61-
})
87+
}))
6288
}
6389
for (const day of agendaStore.meetingDays) {
64-
days.push({
90+
days.push(optionToLink({
6591
label: `Jump to ${day.label}`,
6692
key: day.slug,
6793
icon: () => h('i', { class: 'bi bi-arrow-down-right-square' })
68-
})
94+
}))
6995
}
7096
return days
7197
})
@@ -90,14 +116,13 @@ const downloadIcsOptions = [
90116
function jumpToDay (dayId) {
91117
if (dayId === 'now') {
92118
const lastEventId = agendaStore.findCurrentEventId()
93-
94119
if (lastEventId) {
95120
document.getElementById(`agenda-rowid-${lastEventId}`)?.scrollIntoView(true)
96121
} else {
97122
message.warning('There is no event happening right now.')
98123
}
99124
} else {
100-
document.getElementById(`agenda-day-${dayId}`)?.scrollIntoView(true)
125+
document.getElementById(dayId)?.scrollIntoView(true)
101126
}
102127
}
103128
@@ -162,4 +187,19 @@ function downloadIcs (key) {
162187
}
163188
}
164189
}
190+
191+
.dropdown-link {
192+
display: flex;
193+
text-decoration:none;
194+
gap: 0.2rem 0.5rem;
195+
padding: 0.5em;
196+
color: var(--bs-body-color);
197+
198+
&:hover,
199+
&:focus {
200+
background-color: var(--bs-dark-bg-subtle);
201+
text-decoration: underline;
202+
}
203+
}
204+
165205
</style>

client/agenda/AgendaQuickAccess.vue

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
li.nav-item(v-for='day of agendaStore.meetingDays')
100100
a.nav-link(
101101
:class='agendaStore.dayIntersectId === day.slug ? `active` : ``'
102-
:href='`#slot-` + day.slug'
102+
:href='`#${day.slug}`'
103103
@click='scrollToDay(day.slug, $event)'
104104
)
105105
i.bi.bi-arrow-right-short.d-none.d-xxl-inline.me-2
@@ -109,7 +109,6 @@
109109
<script setup>
110110
import { computed, h } from 'vue'
111111
import { useRoute, useRouter } from 'vue-router'
112-
import { DateTime } from 'luxon'
113112
import {
114113
NAffix,
115114
NBadge,
@@ -200,14 +199,11 @@ function pickerDiscard () {
200199
}
201200
}
202201
203-
function scrollToDay (dayId, ev) {
204-
ev.preventDefault()
205-
document.getElementById(`agenda-day-${dayId}`)?.scrollIntoView(true)
202+
function scrollToDay (daySlug, ev) {
203+
document.getElementById(daySlug)?.scrollIntoView(true)
206204
}
207205
208206
function scrollToNow (ev) {
209-
ev.preventDefault()
210-
211207
const lastEventId = agendaStore.findCurrentEventId()
212208
213209
if (lastEventId) {

client/agenda/AgendaScheduleList.vue

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
)
2525
//- ROW - DAY HEADING -----------------------
2626
template(v-if='item.displayType === `day`')
27-
td(:id='`agenda-day-` + item.id', :colspan='pickerModeActive ? 6 : 5') {{item.date}}
27+
td(:id='item.slug', :colspan='pickerModeActive ? 6 : 5') {{item.date}}
2828
//- ROW - SESSION HEADING -------------------
2929
template(v-else-if='item.displayType === `session-head`')
3030
td.agenda-table-cell-check(v-if='pickerModeActive') &nbsp;
@@ -200,7 +200,7 @@ import {
200200
201201
import AgendaDetailsModal from './AgendaDetailsModal.vue'
202202
203-
import { useAgendaStore } from './store'
203+
import { useAgendaStore, daySlugPrefix, daySlug } from './store'
204204
import { useSiteStore } from '../shared/store'
205205
import { getUrl } from '../shared/urls'
206206
@@ -248,6 +248,7 @@ const meetingEvents = computed(() => {
248248
if (itemDate.toISODate() !== acc.lastDate) {
249249
acc.result.push({
250250
id: item.id,
251+
slug: daySlug(item),
251252
key: `day-${itemDate.toISODate()}`,
252253
displayType: 'day',
253254
date: itemDate.toLocaleString(DateTime.DATE_HUGE),
@@ -575,6 +576,30 @@ function recalculateRedLine () {
575576
}
576577
}
577578
579+
/**
580+
* On page load when browser location hash contains '#now' or '#agenda-day-*' then scroll accordingly
581+
*/
582+
;(function scrollToHashInit() {
583+
if (!window.location.hash) {
584+
return
585+
}
586+
if (!(window.location.hash === "#now" || window.location.hash.startsWith(`#${daySlugPrefix}`))) {
587+
return
588+
}
589+
const unsubscribe = agendaStore.$subscribe((_mutation, agendaStoreState) => {
590+
if (agendaStoreState.schedule.length === 0) {
591+
return
592+
}
593+
unsubscribe() // we only need to scroll once, so unsubscribe from future updates
594+
if(window.location.hash === "#now") {
595+
const lastEventId = agendaStore.findCurrentEventId()
596+
document.getElementById(`agenda-rowid-${lastEventId}`)?.scrollIntoView(true)
597+
} else if(window.location.hash.startsWith(`#${daySlugPrefix}`)) {
598+
document.getElementById(window.location.hash.substring(1))?.scrollIntoView(true)
599+
}
600+
})
601+
})()
602+
578603
// MOUNTED
579604
580605
onMounted(() => {

client/agenda/store.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export const useAgendaStore = defineStore('agenda', {
121121
meetingDays () {
122122
const siteStore = useSiteStore()
123123
return uniqBy(this.scheduleAdjusted, 'adjustedStartDate').sort().map(s => ({
124-
slug: s.id.toString(),
124+
slug: daySlug(s),
125125
ts: s.adjustedStartDate,
126126
label: siteStore.viewport < 1350 ? DateTime.fromISO(s.adjustedStartDate).toFormat('ccc LLL d') : DateTime.fromISO(s.adjustedStartDate).toLocaleString(DateTime.DATE_HUGE)
127127
}))
@@ -292,3 +292,8 @@ function findFirstConferenceUrl (txt) {
292292
} catch (err) { }
293293
return null
294294
}
295+
296+
export const daySlugPrefix = 'agenda-day-'
297+
export function daySlug(s) {
298+
return `${daySlugPrefix}${s.adjustedStartDate}` // eg 'agenda-day-2024-08-13'
299+
}

playwright/tests/meeting/agenda.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ test.describe('past - small screens', () => {
14311431

14321432
// can open the jump to day dropdown
14331433
await barBtnLocator.first().click()
1434-
const jumpDayDdnLocator = page.locator('.n-dropdown-menu > .n-dropdown-option')
1434+
const jumpDayDdnLocator = page.locator('.n-dropdown-menu [data-testid=mobile-link]')
14351435
await expect(jumpDayDdnLocator).toHaveCount(7)
14361436
for (let idx = 0; idx < 7; idx++) {
14371437
const localDateTime = DateTime.fromISO(meetingData.meeting.startDate, { zone: meetingData.meeting.timezone })

0 commit comments

Comments
 (0)