From 08e70e68c05483a85a8a3944bce75418605af06c Mon Sep 17 00:00:00 2001 From: Minh Duong Date: Fri, 3 Jan 2025 01:50:44 -0600 Subject: [PATCH 1/4] feat: display meeting indexes by semester fix: improve calendar event handling and metadata refactor: update button class names and styles across multiple components --- _global/components/Icons/fluentui.tsx | 36 ++++ _global/content/events/fallctf/2023/index.mdx | 2 +- .../fa2023/general/2023-11-02/index.mdx | 2 +- _global/utils/meetingMetadata.ts | 61 +++--- fallctf.com/src/pages/2024.astro | 2 +- fallctf.com/src/pages/[...slug].astro | 2 +- fallctf.com/src/styles/fallctf.css | 9 +- .../src/components/CalendarSubscribe.tsx | 7 +- sigpwny.com/src/components/DropdownSelect.tsx | 45 +++++ .../index.tsx => Meeting/Controls.tsx} | 0 sigpwny.com/src/components/Meeting/Row.astro | 12 +- sigpwny.com/src/components/Menu/index.tsx | 9 +- sigpwny.com/src/components/Menu/styles.css | 2 +- sigpwny.com/src/layouts/Meeting.astro | 28 +-- sigpwny.com/src/layouts/MeetingIndex.astro | 15 ++ sigpwny.com/src/pages/applecal.astro | 2 +- sigpwny.com/src/pages/cal.astro | 2 +- .../src/pages/calendar/[...type]/apple.ics.ts | 7 +- .../pages/calendar/[...type]/generic.ics.ts | 7 +- sigpwny.com/src/pages/events-temp.astro | 2 +- sigpwny.com/src/pages/index.astro | 4 +- sigpwny.com/src/pages/join.astro | 4 +- .../pages/meetings/[...semester]/index.astro | 189 ++++++++++++++++++ .../src/pages/meetings/[...slug]/index.astro | 12 +- sigpwny.com/src/pages/meetings/all.astro | 35 ++++ sigpwny.com/src/pages/meetings/index.astro | 111 +--------- sigpwny.com/src/semesters.json | 43 ++++ sigpwny.com/src/styles/main.css | 18 +- sigpwny.com/src/utils/meetings.ts | 33 +++ .../src/utils/reactMeetingMetadata.tsx | 5 + 30 files changed, 496 insertions(+), 210 deletions(-) create mode 100644 sigpwny.com/src/components/DropdownSelect.tsx rename sigpwny.com/src/components/{MeetingControls/index.tsx => Meeting/Controls.tsx} (100%) create mode 100644 sigpwny.com/src/layouts/MeetingIndex.astro create mode 100644 sigpwny.com/src/pages/meetings/[...semester]/index.astro create mode 100644 sigpwny.com/src/pages/meetings/all.astro create mode 100644 sigpwny.com/src/semesters.json diff --git a/_global/components/Icons/fluentui.tsx b/_global/components/Icons/fluentui.tsx index 2290c6491..e73474f33 100644 --- a/_global/components/Icons/fluentui.tsx +++ b/_global/components/Icons/fluentui.tsx @@ -84,12 +84,36 @@ export const ChevronCircleRightRegular = (props: TSVGElementProps) => ( ); +export const ChevronLeftFilled = (props: TSVGElementProps) => ( + + + +); + +export const ChevronLeftRegular = (props: TSVGElementProps) => ( + + + +); + +export const ChevronRightFilled = (props: TSVGElementProps) => ( + + + +); + export const ChevronRightRegular = (props: TSVGElementProps) => ( ); +export const ChevronUpDownFilled = (props: TSVGElementProps) => ( + + + +); + export const ClockRegular = (props: TSVGElementProps) => ( @@ -114,6 +138,18 @@ export const HatGraduationRegular = (props: TSVGElementProps) => ( ); +export const InfoFilled = (props: TSVGElementProps) => ( + + + +); + +export const InfoRegular = (props: TSVGElementProps) => ( + + + +); + export const LinkRegular = (props: TSVGElementProps) => ( diff --git a/_global/content/events/fallctf/2023/index.mdx b/_global/content/events/fallctf/2023/index.mdx index 68032f96c..687faa19b 100644 --- a/_global/content/events/fallctf/2023/index.mdx +++ b/_global/content/events/fallctf/2023/index.mdx @@ -32,7 +32,7 @@ links: ## Registration Registration for the CTF competition platform is now available! -Register on CTFd +Register on CTFd

Registration via Google Forms for a free shirt and electronic badge has closed. If you previously registered beforehand, please make sure to bring your iCard to the event (or show your ID on the Illinois app). If you did not register on Google Forms, we will be handing out any remaining shirts later in the event. We will also be raffling off extra electronic badges. diff --git a/_global/content/meetings/fa2023/general/2023-11-02/index.mdx b/_global/content/meetings/fa2023/general/2023-11-02/index.mdx index 3b388621a..22bf0d1f6 100644 --- a/_global/content/meetings/fa2023/general/2023-11-02/index.mdx +++ b/_global/content/meetings/fa2023/general/2023-11-02/index.mdx @@ -23,4 +23,4 @@ We are excited to have both our sponsor CrowdStrike and UIUC's Privacy and Cyber Pizza will be provided! -Live Scavenger Hunt \ No newline at end of file +Live Scavenger Hunt \ No newline at end of file diff --git a/_global/utils/meetingMetadata.ts b/_global/utils/meetingMetadata.ts index e5a04df16..d5f3ed1fa 100644 --- a/_global/utils/meetingMetadata.ts +++ b/_global/utils/meetingMetadata.ts @@ -1,32 +1,43 @@ export const meetingMetatypes = [ - 'general', - 'ctf', - 'purple', - 'embedded', - ]; - + 'general', + 'seminar', + 'ctf', + 'purple', + 'embedded', +]; + export type MeetingMetatype = typeof meetingMetatypes[number]; export interface MeetingMetadata { -name: string; -shortName: string; -} + name: string; + shortName: string; + description?: string; +}; export const meetingMetadata: Record = { - 'general': { - name: 'General', - shortName: 'General', - }, - 'ctf': { - name: 'CTF Team', - shortName: 'CTF', - }, - 'purple': { - name: 'Purple Team', - shortName: 'Purple', - }, - 'embedded': { - name: 'Embedded Team', - shortName: 'Embedded', - }, + 'general': { + name: 'General Meetings', + shortName: 'General', + description: 'Attend our weekly general meetings to learn fundamental skills in cybersecurity.', + }, + 'seminar': { + name: 'Seminar Meetings', + shortName: 'Seminar', + description: 'Attend our seminars to discuss advanced and novel research topics in cybersecurity.', + }, + 'ctf': { + name: 'CTF Team', + shortName: 'CTF', + description: 'Compete in "Capture the Flag" events to hone your cybersecurity skills.', + }, + 'purple': { + name: 'Purple Team', + shortName: 'Purple', + description: 'Learn red-teaming (offensive) and blue-teaming (defensive) skills to secure systems and networks.', + }, + 'embedded': { + name: 'Embedded Team', + shortName: 'Embedded', + description: 'Build secure embedded systems and learn about hardware hacking!', + }, }; \ No newline at end of file diff --git a/fallctf.com/src/pages/2024.astro b/fallctf.com/src/pages/2024.astro index e90f61295..9a7384937 100644 --- a/fallctf.com/src/pages/2024.astro +++ b/fallctf.com/src/pages/2024.astro @@ -82,7 +82,7 @@ const event = { {event.links.map((link) => ( {link.name} diff --git a/fallctf.com/src/pages/[...slug].astro b/fallctf.com/src/pages/[...slug].astro index af63b8d90..799b77975 100644 --- a/fallctf.com/src/pages/[...slug].astro +++ b/fallctf.com/src/pages/[...slug].astro @@ -54,7 +54,7 @@ const flavor = 'Fall CTF is a beginner-friendly CTF competition for UIUC student {event.links.map((link) => ( {link.name} diff --git a/fallctf.com/src/styles/fallctf.css b/fallctf.com/src/styles/fallctf.css index a479de31c..8265d9b34 100644 --- a/fallctf.com/src/styles/fallctf.css +++ b/fallctf.com/src/styles/fallctf.css @@ -67,12 +67,11 @@ h3 { .panel-p-0 { @apply bg-surface-100 rounded-xl; } -.btn-primary { - @apply bg-primary text-surface-000 px-3 py-1 rounded-full cursor-pointer; +.button { + @apply border-0 rounded-md px-3 py-1 cursor-pointer select-none; } -.btn-primary:hover { - background-color: rgb(var(--rgb-secondary)); - color: rgb(var(--rgb-surface-000)); +.btn-primary { + @apply bg-primary hover:bg-secondary text-surface-000 hover:text-surface-000; } .button { @apply flex flex-row items-center gap-1 px-3 py-1 cursor-pointer rounded-md; diff --git a/sigpwny.com/src/components/CalendarSubscribe.tsx b/sigpwny.com/src/components/CalendarSubscribe.tsx index 207463ad6..71e5483e3 100644 --- a/sigpwny.com/src/components/CalendarSubscribe.tsx +++ b/sigpwny.com/src/components/CalendarSubscribe.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import type { Placement } from '@floating-ui/react'; import { Popover, PopoverTrigger, @@ -25,7 +26,7 @@ import { type MeetingMetatype } from '$/utils/meetingMetadata'; interface CalendarSubscribeProps { selected: MeetingMetatype[]; - placement?: 'top' | 'bottom' | 'left' | 'right'; + placement?: Placement; } export default function CalendarSubscribe({ selected, placement }: CalendarSubscribeProps) { @@ -54,7 +55,7 @@ export default function CalendarSubscribe({ selected, placement }: CalendarSubsc

setOpen(!open)} - className={`btn-primary flex flex-row gap-2 items-center ${open ? "ring-primary ring-2 ring-offset-2 ring-offset-surface-000" : ""}`} + className={`button btn-primary flex flex-row gap-2 items-center ${open ? "ring-primary ring-2 ring-offset-2 ring-offset-surface-000" : ""}`} > @@ -65,7 +66,7 @@ export default function CalendarSubscribe({ selected, placement }: CalendarSubsc
- +
    {Object.entries(reactMeetingMetadata).map(([meeting_type, metadata]) => (
  • void; + placement?: Placement; +} + +export default function DropdownSelect(props: DropdownSelectProps) { + const [open, setOpen] = useState(false); + const selectedText = props.displayText ?? props.options.find((option) => option.id === props.selectedId)?.displayText ?? props.selectedId; + + return ( + + setOpen(!open)} + className={`button flex flex-row gap-2 items-center justify-between bg-surface-100 hover:bg-surface-150 text-white w-full border border-surface-200 pr-1 ${open ? "ring-primary ring-2 ring-offset-2 ring-offset-surface-000" : ""}`} + > + {selectedText} + + + + {props.children} + + + ); +}; \ No newline at end of file diff --git a/sigpwny.com/src/components/MeetingControls/index.tsx b/sigpwny.com/src/components/Meeting/Controls.tsx similarity index 100% rename from sigpwny.com/src/components/MeetingControls/index.tsx rename to sigpwny.com/src/components/Meeting/Controls.tsx diff --git a/sigpwny.com/src/components/Meeting/Row.astro b/sigpwny.com/src/components/Meeting/Row.astro index 29ec4fc7f..5d45a1669 100644 --- a/sigpwny.com/src/components/Meeting/Row.astro +++ b/sigpwny.com/src/components/Meeting/Row.astro @@ -6,29 +6,29 @@ import { CountdownBadge } from '@/components/ReactMigration/Countdown'; import { TagGroup } from '@/components/ReactMigration/Tag'; import { convertDate, weekNumber } from '@/utils/meetings'; import { getProfilesFromNames } from '$/utils/profiles'; +import type { Meeting } from '@/utils/meetings'; import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; import utc from 'dayjs/plugin/utc'; import UpcomingMeta from '@/components/ReactMigration/UpcomingMeta'; -import type { MeetingType } from '@/pages/meetings/index.astro'; dayjs.extend(duration); dayjs.extend(utc); interface Props { - input: MeetingType; - showUpcoming: boolean; + input: Meeting; + hideUpcoming?: boolean; } -const { input, showUpcoming } = Astro.props; +const { input, hideUpcoming } = Astro.props; const meeting = input.data; const time_close = dayjs(meeting.time_start).add(dayjs.duration(meeting.duration)).toDate(); // Resolve credit names to profiles const profiles = await getProfilesFromNames(meeting.credit); -const upcomingVisibility = showUpcoming ? 'block' : 'none'; -const notUpcomingVisibility = showUpcoming ? 'none' : 'block'; +const upcomingVisibility = hideUpcoming ? 'none' : 'block'; +const notUpcomingVisibility = hideUpcoming ? 'none' : 'block'; --- -
  • - -
    -
    - - + +
  • +
    +
    +
    + + +
    {meeting.week_number != null ? ( - Week {weekNumber(meeting.week_number)} + ) : null} {meeting.title}
    - -
    diff --git a/sigpwny.com/src/components/Meeting/TypeBadge.tsx b/sigpwny.com/src/components/Meeting/TypeBadge.tsx index 110a8e689..53f4189ce 100644 --- a/sigpwny.com/src/components/Meeting/TypeBadge.tsx +++ b/sigpwny.com/src/components/Meeting/TypeBadge.tsx @@ -4,16 +4,43 @@ import { type ReactMeetingMetadata, } from '@/utils/reactMeetingMetadata'; -export default function MeetingTypeBadge({ type }: { type: MeetingMetatype }) { +interface Props { + type: MeetingMetatype; + fullName?: boolean; + consistentWidth?: boolean; +}; + +export default function MeetingTypeBadge({ type, fullName, consistentWidth }: Props) { const metadata = reactMeetingMetadata[type] ?? { name: type, shortName: type, color: 'rgb(var(--rgb-pwny-green))', } as ReactMeetingMetadata; - return ( -
    + const nameToUse = fullName ? "name" : "shortName"; + // Calculate max length of the name being used across the input metadata and reactMeetingMetadata + // This is used to calculate a consistent width for the badge + // It's not the most elegant solution and doesn't scale well with longer names... but it works + const maxNameLength = Math.max( + metadata[nameToUse].length, + ...[...Object.values(reactMeetingMetadata)].map((metadata) => metadata[nameToUse].length) + ); + const badge = ( +
    {metadata.icon ?? null} - {metadata.shortName} + {metadata[nameToUse]}
    ); + if (consistentWidth) { + return ( + + {badge} + + ) + } + return badge; }; \ No newline at end of file diff --git a/sigpwny.com/src/components/Menu/styles.css b/sigpwny.com/src/components/Menu/styles.css index 4b482e323..5807f95cd 100644 --- a/sigpwny.com/src/components/Menu/styles.css +++ b/sigpwny.com/src/components/Menu/styles.css @@ -8,5 +8,5 @@ .pwny-menu a, .pwny-menu button { - @apply w-full !text-white flex flex-row grow gap-2 items-center px-1 rounded-md ring-2 ring-transparent ring-offset-0 hover:bg-surface-250 focus:outline-none focus-visible:ring-white transition-colors; + @apply drag-none w-full text-white flex flex-row grow gap-2 items-center px-1 rounded-md ring-2 ring-transparent ring-offset-0 hover:bg-surface-250 focus:outline-none focus-visible:ring-white transition-colors; } \ No newline at end of file diff --git a/sigpwny.com/src/components/ReactMigration/UpcomingMeta.tsx b/sigpwny.com/src/components/ReactMigration/UpcomingMeta.tsx deleted file mode 100644 index 26f696365..000000000 --- a/sigpwny.com/src/components/ReactMigration/UpcomingMeta.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useEffect, useState } from 'react'; - -export default function UpcomingMeta({ end }: { end: Date }) { - const [isUpcoming, setIsUpcoming] = useState(end > new Date()); - useEffect(() => { - setIsUpcoming(end > new Date()); - const interval = setInterval(() => { - setIsUpcoming(end > new Date()); - }, 60000); - return () => clearInterval(interval); - }, [end]); - return ( -
    - ) -} \ No newline at end of file diff --git a/sigpwny.com/src/layouts/MeetingIndex.astro b/sigpwny.com/src/layouts/MeetingIndex.astro index 40959de86..609b72952 100644 --- a/sigpwny.com/src/layouts/MeetingIndex.astro +++ b/sigpwny.com/src/layouts/MeetingIndex.astro @@ -34,7 +34,7 @@ const ButtonElementOlder = olderLink ? Link : 'span'; title="Meetings" description="Index of SIGPwny meetings" > -
    +

    Meetings