diff --git a/server/src/routes.js b/server/src/routes.js index 335265c7..ef11148b 100644 --- a/server/src/routes.js +++ b/server/src/routes.js @@ -247,19 +247,20 @@ module.exports = ({ app, Cache, io }) => { ].map(hex => parseInt(hex, 16)).join(":"); } - async function generateCal(event) { - let theme = (event.theme ? await Cache.get(event.theme[0]) : null); - let matches = await Promise.all((event.matches || []).map(id => Cache.get(id))); + async function generateCal({ team, event }) { + const matchContainer = team || event; + let theme = (matchContainer.theme ? await Cache.get(matchContainer.theme[0]) : null); + let matches = await Promise.all((matchContainer.matches || []).map(id => Cache.get(id))); matches = matches.filter(m => m?.start).map(m => getMatchCal(m, event)); if (!matches.length) return null; let cal = [ "BEGIN:VCALENDAR", "VERSION:2.0", - "PRODID:-//2022//SLMN.GG//EN", + "PRODID:-//2023//SLMN.GG//EN", "METHOD:PUBLISH", "CALSCALE:GREGORIAN", - `NAME:${event.name} (SLMN.GG)`, - `X-WR-CALNAME:${event.name} (SLMN.GG)`, + `NAME:${matchContainer.name} (SLMN.GG)`, + `X-WR-CALNAME:${matchContainer.name} (SLMN.GG)`, `COLOR:${theme ? getCalCol(theme.color_theme) : "64:64:64"}`, "REFRESH-INTERVAL;VALUE=DURATION:PT10M", "X-PUBLISHED-TTL:PT10M" @@ -276,14 +277,26 @@ module.exports = ({ app, Cache, io }) => { app.get("/ical", async (req, res) => { try { - if (!req.query.event) return res.status(400).send("The 'event' query is required"); - let event = await Cache.get(req.query.event); - if (!event || event.__tableName !== "Events") return res.status(400).send("Unknown event"); - - let ical = await generateCal(event); - if (!ical) return res.status(400).send("No matches scheduled"); + if (!req.query.event && !req.query.team) return res.status(400).send("You must specify a 'team' or 'event'"); + if (req.query.event && req.query.team) return res.status(400).send("You must specify only one of 'team' or 'event'"); + if (req.query.team) { + let team = await Cache.get(req.query.team); + if (!team || team.__tableName !== "Teams") return res.status(400).send("Unknown team"); + + let event = await Cache.get(team.event?.[0]); + if (!event || event.__tableName !== "Events") return res.status(400).send("Did not find an event for this team"); + + let ical = await generateCal({ team, event }); + if (!ical) return res.status(400).send("No matches scheduled"); + return res.header("Content-Type", "text/calendar").send(ical); + } else { + let event = await Cache.get(req.query.event); + if (!event || event.__tableName !== "Events") return res.status(400).send("Unknown event"); - return res.header("Content-Type", "text/calendar").send(ical); + let ical = await generateCal({ event }); + if (!ical) return res.status(400).send("No matches scheduled"); + return res.header("Content-Type", "text/calendar").send(ical); + } } catch (e) { console.error(e); return res.status(500).send(e.message); diff --git a/website/src/components/website/AddToCalendar.vue b/website/src/components/website/AddToCalendar.vue new file mode 100644 index 00000000..a01d3b8f --- /dev/null +++ b/website/src/components/website/AddToCalendar.vue @@ -0,0 +1,73 @@ + + + + Automatically sync all {{ target.name }} matches to your calendar. + + + + Google + Calendar + + + Outlook + + Apple + + + Or copy this link to your clipboard and add it to your calendar manually: + {{ calendarURL }} + + + + Sync calendar + + + + + diff --git a/website/src/components/website/schedule/TimezoneSwapper.vue b/website/src/components/website/schedule/TimezoneSwapper.vue index 5c683f27..5e2ab2b4 100644 --- a/website/src/components/website/schedule/TimezoneSwapper.vue +++ b/website/src/components/website/schedule/TimezoneSwapper.vue @@ -66,4 +66,8 @@ export default { .timezone-swapper:not(.align-left) option { direction: rtl; } + +.timezone-swapper:not(.align-left) .form-group { + margin-bottom: 0; +} diff --git a/website/src/utils/fetch.js b/website/src/utils/fetch.js index e6e6e1e7..946cb6ea 100644 --- a/website/src/utils/fetch.js +++ b/website/src/utils/fetch.js @@ -14,7 +14,7 @@ export function getDataServerAddress() { if (import.meta.env.VITE_DATA_SERVER) return import.meta.env.VITE_DATA_SERVER; if (import.meta.env.VITE_DEPLOY_MODE === "local") { - return `//${window.location.hostname}:8901`; + return `${window.location.protocol}//${window.location.hostname}:8901`; } return "https://data.slmn.gg"; } diff --git a/website/src/views/sub-views/event/EventSchedule.vue b/website/src/views/sub-views/event/EventSchedule.vue index fe714f09..be599553 100644 --- a/website/src/views/sub-views/event/EventSchedule.vue +++ b/website/src/views/sub-views/event/EventSchedule.vue @@ -1,19 +1,31 @@ - - - - - + + Schedule + + + + + + Settings & Sync + + + + + + + + + + - Schedule ({ activeScheduleNum: useRouteQuery("page", undefined, { transform: val => val === "all" ? val : parseInt(val), mode: "replace" }), hideCompleted: false, hideNoVods: false, - selectedBroadcastID: null + selectedBroadcastID: null, + showSettings: false }), computed: { showAll() { @@ -274,4 +288,17 @@ export default { margin-top: 1.5em; } } + + .top-right-settings { + position: absolute; + top: 0; + right: 0; + } + .top-right-settings .group-content { + z-index: 100; + box-shadow: 0 0 4px 2px #202020; + } + .schedule-title { + position: relative; + } diff --git a/website/src/views/sub-views/team/TeamSchedule.vue b/website/src/views/sub-views/team/TeamSchedule.vue index 99c01136..d3cef02a 100644 --- a/website/src/views/sub-views/team/TeamSchedule.vue +++ b/website/src/views/sub-views/team/TeamSchedule.vue @@ -1,6 +1,23 @@ - Team matches + + Schedule + + + + + + Settings & Sync + + + + + + + + + +
Automatically sync all {{ target.name }} matches to your calendar.
Or copy this link to your clipboard and add it to your calendar manually:
{{ calendarURL }}