Skip to content

Commit

Permalink
feat(ui): calendar sidebar redesign (#464)
Browse files Browse the repository at this point in the history
* feat: update calendar sidebar, footer, and header with Figma design

* chore: run lint

* feat: update header with Figma design

* chore: run lint

* chore: remove unused vars

* chore: fix types

* fix: adjust sidebar minimum width

* fix: update LogoIcon layout to ensure text is always displayed

* feat: add spacing constants

* fix: add sidebar styling with spacing system and sticky header

* fix: update spacing constants to use rem units

* refactor: replace padding with spacing system and colors with UTRP theme

* refactor: rename ImportantLinks to ResourceLinks

* refactor: simplify CalendarHeader button component by using icon prop

* feat: add sidebar open and close transition

* refactor: rename unused var

* fix: update social icon color

* feat: improve layout and spacing in calendar components

* refactor: remove unused GearSix icon and options handler

* feat: update calendar components with new icons and improved spacing

* fix: correct class name

* refactor: organize social links into array and update link styling

* refactor: remove unused import

* fix: adjust gap spacing in radio button

* fix: update divider component to use theme offwhite1

* fix: increase size of outward arrow icon

* feat: add getSpacingInPx function to convert rem to pixels

* fix: update gap spacing in CalendarSchedules component to use spacing system

* fix: rollback footer social icons to original icons

* fix: update Calendar styles to use theme offwhite1 and adjust padding to account for scrollbar

* fix: update LargeLogo component to use gap-spacing-3

* fix: update button variants to 'minimal' and adjust styles for consistency

* fix: adjust padding in Calendar component for better layout consistency

* fix: increase size of arrow icon

* fix: add shrink-0 to radio buttons
  • Loading branch information
EthanL06 authored Jan 20, 2025
1 parent 52347fd commit 843cb5b
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 114 deletions.
12 changes: 12 additions & 0 deletions src/shared/types/Spacing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@ export const spacing = {
'spacing-7': '1.5rem',
'spacing-8': '2rem',
} as const;

type SpacingKey = keyof typeof spacing;

/**
* Converts a spacing value from rem to pixels
* @param key - The spacing key to convert
* @returns The spacing value in pixels
*/
export function getSpacingInPx(key: SpacingKey): number {
const remValue = parseFloat(spacing[key]);
return remValue * 16; // 1rem = 16px
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import type { Meta, StoryObj } from '@storybook/react';
import ImportantLinks from '@views/components/calendar/ImportantLinks';
import ResourceLinks from '@views/components/calendar/ResourceLinks';

const meta = {
title: 'Components/Common/ImportantLinks',
component: ImportantLinks,
title: 'Components/Common/ResourceLinks',
component: ResourceLinks,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {},
} satisfies Meta<typeof ImportantLinks>;
} satisfies Meta<typeof ResourceLinks>;
export default meta;

type Story = StoryObj<typeof meta>;
Expand Down
90 changes: 70 additions & 20 deletions src/views/components/calendar/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import { Sidebar } from '@phosphor-icons/react';
import type { CalendarTabMessages } from '@shared/messages/CalendarMessages';
import type { Course } from '@shared/types/Course';
import { CRX_PAGES } from '@shared/types/CRXPages';
import { openReportWindow } from '@shared/util/openReportWindow';
import CalendarBottomBar from '@views/components/calendar/CalendarBottomBar';
import CalendarGrid from '@views/components/calendar/CalendarGrid';
import CalendarHeader from '@views/components/calendar/CalendarHeader';
import { CalendarSchedules } from '@views/components/calendar/CalendarSchedules';
import ImportantLinks from '@views/components/calendar/ImportantLinks';
import ResourceLinks from '@views/components/calendar/ResourceLinks';
import Divider from '@views/components/common/Divider';
import CourseCatalogInjectedPopup from '@views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup';
import { CalendarContext } from '@views/contexts/CalendarContext';
import useCourseFromUrl from '@views/hooks/useCourseFromUrl';
import { useFlattenedCourseSchedule } from '@views/hooks/useFlattenedCourseSchedule';
import { MessageListener } from 'chrome-extension-toolkit';
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';

import CalendarFooter from './CalendarFooter';
import TeamLinks from './TeamLinks';
import OutwardArrowIcon from '~icons/material-symbols/arrow-outward';

import { Button } from '../common/Button';
import { LargeLogo } from '../common/LogoIcon';
import Text from '../common/Text/Text';
import CalendarFooter from './CalendarFooter';
/**
* Calendar page component
*/
Expand Down Expand Up @@ -54,25 +61,68 @@ export default function Calendar(): JSX.Element {
return (
<CalendarContext.Provider value>
<div className='h-full w-full flex flex-col'>
<CalendarHeader
onSidebarToggle={() => {
setShowSidebar(!showSidebar);
}}
/>
<div className='h-full flex overflow-auto pl-3'>
{showSidebar && (
<div className='h-full flex flex-none flex-col justify-between pb-5 screenshot:hidden'>
<div className='mb-3 h-full w-fit flex flex-col overflow-auto pb-2 pl-4.5 pr-4 pt-5'>
<CalendarSchedules />
<Divider orientation='horizontal' size='100%' className='my-5' />
<ImportantLinks />
<Divider orientation='horizontal' size='100%' className='my-5' />
<TeamLinks />
</div>
<CalendarFooter />
<div className='h-screen flex overflow-auto'>
<div
className={clsx(
'py-spacing-6 relative h-full min-h-screen w-full flex flex-none flex-col justify-between overflow-clip whitespace-nowrap border-r border-theme-offwhite1 shadow-[2px_0_10px,rgba(214_210_196_/_.1)] duration-300 ease-out-expo transition-property-max-width screenshot:hidden',
{
'max-w-[20.3125rem] ': showSidebar,
'max-w-0 pointer-events-none': !showSidebar,
}
)}
tabIndex={showSidebar ? 0 : -1}
aria-hidden={!showSidebar}
{...{ inert: !showSidebar ? '' : undefined }}
>
<div className='sticky top-0 z-50 w-full flex items-center justify-between gap-x-3xl bg-white px-spacing-8 pb-spacing-6'>
<LargeLogo />
<Button
variant='minimal'
color='theme-black'
onClick={() => {
setShowSidebar(!showSidebar);
}}
className='h-fit screenshot:hidden !p-0'
icon={Sidebar}
/>
</div>

<div
style={{
scrollbarGutter: 'stable',
}}
className='relative h-full w-full flex grow flex-col gap-y-spacing-6 overflow-x-clip overflow-y-auto pb-spacing-6 pl-spacing-8 pr-4.5'
>
<CalendarSchedules />
<Divider orientation='horizontal' size='100%' />
<ResourceLinks />
<Divider orientation='horizontal' size='100%' />
{/* <TeamLinks /> */}
<a
href={CRX_PAGES.REPORT}
className='flex items-center gap-spacing-2 text-ut-burntorange underline-offset-2 hover:underline'
target='_blank'
rel='noreferrer'
onClick={event => {
event.preventDefault();
openReportWindow();
}}
>
<Text variant='p'>Send us Feedback!</Text>
<OutwardArrowIcon className='h-4 w-4' />
</a>
</div>
)}

<CalendarFooter />
</div>

<div className='h-full min-w-5xl flex flex-grow flex-col overflow-y-auto'>
<CalendarHeader
sidebarOpen={showSidebar}
onSidebarToggle={() => {
setShowSidebar(!showSidebar);
}}
/>
<div className='min-h-2xl flex-grow overflow-auto pl-2 pr-4 pt-6 screenshot:min-h-xl'>
<CalendarGrid courseCells={courseCells} setCourse={setCourse} />
</div>
Expand Down
73 changes: 52 additions & 21 deletions src/views/components/calendar/CalendarFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,71 @@
import { GearSix } from '@phosphor-icons/react';
import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript';
import React from 'react';

import DiscordIcon from '~icons/bi/discord';
import GithubIcon from '~icons/ri/github-fill';
import InstagramIcon from '~icons/ri/instagram-line';
import LinkedinIcon from '~icons/ri/linkedin-box-fill';

import { Button } from '../common/Button';
import Link from '../common/Link';

interface SocialLink {
icon: React.FC<React.SVGProps<SVGSVGElement>>;
url: string;
}

const socialLinks: SocialLink[] = [
{
icon: InstagramIcon,
url: 'https://www.instagram.com/longhorndevelopers',
},
{
icon: DiscordIcon,
url: 'https://discord.gg/7pQDBGdmb7',
},
{
icon: GithubIcon,
url: 'https://github.com/Longhorn-Developers',
},
{
icon: LinkedinIcon,
url: 'https://www.linkedin.com/company/longhorn-developers/posts/?feedView=all',
},
];

/**
* Opens the options page in a new tab.
* @returns A promise that resolves when the options page is opened.
*/
const handleOpenOptions = async (): Promise<void> => {
const url = chrome.runtime.getURL('/options.html');
await openTabFromContentScript(url);
};

/**
* The footer section of the calendar's sidebar
* @returns
*/
export default function CalendarFooter(): JSX.Element {
return (
<footer className='min-w-full w-0 pl-4.5 space-y-2'>
<div className='flex gap-2'>
<Link className='linkanimate' href='https://www.instagram.com/longhorndevelopers'>
<InstagramIcon className='h-6 w-6' />
</Link>
<Link className='linkanimate' href='https://discord.gg/7pQDBGdmb7'>
<DiscordIcon className='h-6 w-6' />
</Link>
<Link className='linkanimate' href='https://github.com/Longhorn-Developers'>
<GithubIcon className='h-6 w-6' />
</Link>
<Link
className='linkanimate'
href='https://www.linkedin.com/company/longhorn-developers/posts/?feedView=all'
>
<LinkedinIcon className='h-6 w-6 -mx-0.75' />
</Link>
<footer className='min-w-full w-0 flex items-center justify-between bg-white px-spacing-8 pt-spacing-4'>
<div className='flex gap-spacing-5'>
{socialLinks.map(({ icon: Icon, url }) => (
<Link className='linkanimate' href={url}>
<Icon className='h-6 w-6' />
</Link>
))}
</div>
<div>
<Button
className='h-fit w-fit !p-0'
variant='minimal'
icon={GearSix}
color='ut-black'
onClick={handleOpenOptions}
/>
</div>
<p className='text-2.5 text-ut-gray font-light tracking-wide'>
UT Registration Plus is a project under Longhorn Developers, a student-led organization aimed at
addressing issues at UT Austin.
</p>
</footer>
);
}
43 changes: 18 additions & 25 deletions src/views/components/calendar/CalendarHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,22 @@
import { GearSix, Sidebar } from '@phosphor-icons/react';
import { Sidebar } from '@phosphor-icons/react';
import { initSettings, OptionsStore } from '@shared/storage/OptionsStore';
import { Button } from '@views/components/common/Button';
import CourseStatus from '@views/components/common/CourseStatus';
import Divider from '@views/components/common/Divider';
import { LargeLogo } from '@views/components/common/LogoIcon';
import ScheduleTotalHoursAndCourses from '@views/components/common/ScheduleTotalHoursAndCourses';
import useSchedules from '@views/hooks/useSchedules';
import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript';
import React, { useEffect, useState } from 'react';

/**
* Opens the options page in a new tab.
* @returns A promise that resolves when the options page is opened.
*/
const handleOpenOptions = async (): Promise<void> => {
const url = chrome.runtime.getURL('/options.html');
await openTabFromContentScript(url);
};

interface CalendarHeaderProps {
sidebarOpen?: boolean;
onSidebarToggle?: () => void;
}

/**
* Renders the header component for the calendar.
* @returns The JSX element representing the calendar header.
*/
export default function CalendarHeader({ onSidebarToggle }: CalendarHeaderProps): JSX.Element {
export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: CalendarHeaderProps): JSX.Element {
const [enableCourseStatusChips, setEnableCourseStatusChips] = useState<boolean>(false);
const [_enableDataRefreshing, setEnableDataRefreshing] = useState<boolean>(false);

Expand Down Expand Up @@ -55,23 +45,27 @@ export default function CalendarHeader({ onSidebarToggle }: CalendarHeaderProps)
}, []);

return (
<div className='flex items-center gap-5 overflow-x-auto overflow-y-hidden border-b border-ut-offwhite px-7 py-4 md:overflow-x-hidden'>
<Button
variant='minimal'
icon={Sidebar}
color='ut-gray'
onClick={onSidebarToggle}
className='screenshot:hidden'
/>
<LargeLogo />
<Divider className='mx-2 self-center md:mx-4' size='2.5rem' orientation='vertical' />
<div className='flex-1 screenshot:transform-origin-left screenshot:scale-120'>
<div className='min-h-[91px] flex items-center gap-5 overflow-x-auto overflow-y-hidden px-7 py-4 md:overflow-x-hidden'>
{!sidebarOpen && (
<Button
variant='minimal'
color='theme-black'
onClick={onSidebarToggle}
className='h-fit w-fit screenshot:hidden !p-0'
icon={Sidebar}
/>
)}

<div className='screenshot:transform-origin-left screenshot:scale-120'>
<ScheduleTotalHoursAndCourses
scheduleName={activeSchedule.name}
totalHours={activeSchedule.hours}
totalCourses={activeSchedule.courses.length}
/>
</div>

<Divider className='mx-2 self-center md:mx-4 screenshot:hidden' size='2.5rem' orientation='vertical' />

<div className='hidden flex-row items-center justify-end gap-6 screenshot:hidden lg:flex'>
{enableCourseStatusChips && (
<>
Expand All @@ -83,7 +77,6 @@ export default function CalendarHeader({ onSidebarToggle }: CalendarHeaderProps)

{/* <Button variant='single' icon={UndoIcon} color='ut-black' />
<Button variant='single' icon={RedoIcon} color='ut-black' /> */}
<Button variant='minimal' icon={GearSix} color='theme-black' onClick={handleOpenOptions} />
</div>
</div>
);
Expand Down
19 changes: 13 additions & 6 deletions src/views/components/calendar/CalendarSchedules.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import createSchedule from '@pages/background/lib/createSchedule';
import { Plus } from '@phosphor-icons/react';
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
import { getSpacingInPx } from '@shared/types/Spacing';
import { Button } from '@views/components/common/Button';
import List from '@views/components/common/List';
import ScheduleListItem from '@views/components/common/ScheduleListItem';
Expand All @@ -26,16 +27,22 @@ export function CalendarSchedules() {
};

return (
<div className='min-w-full w-0 items-center'>
<div className='m0 m-b-2 w-full flex justify-between'>
<Text variant='h3' className='text-nowrap'>
<div className='min-w-full w-0 flex flex-col items-center gap-y-spacing-3'>
<div className='m0 w-full flex justify-between'>
<Text variant='h3' className='text-nowrap text-theme-black'>
MY SCHEDULES
</Text>
<Button size='mini' variant='minimal' color='theme-black' onClick={handleAddSchedule} icon={Plus} />
<Button
variant='minimal'
color='theme-black'
className='h-fit w-fit !p-0 btn'
onClick={handleAddSchedule}
icon={Plus}
/>
</div>
<div className='flex flex-col space-y-2.5'>
<div className='w-full flex flex-col'>
<List
gap={10}
gap={getSpacingInPx('spacing-3')}
draggables={schedules}
itemKey={s => s.id}
onReordered={reordered => {
Expand Down
Loading

0 comments on commit 843cb5b

Please sign in to comment.