chore: merge branch 'main' into sgunter/button-component
This commit is contained in:
19
src/stories/components/CalendarGrid.stories.tsx
Normal file
19
src/stories/components/CalendarGrid.stories.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
// Calendar.stories.tsx
|
||||
import React from 'react';
|
||||
import Calendar from '@views/components/common/CalendarGrid/CalendarGrid';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Common/Calendar',
|
||||
component: Calendar,
|
||||
parameters: {
|
||||
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
||||
layout: 'centered',
|
||||
tags: ['autodocs'],
|
||||
}
|
||||
} satisfies Meta<typeof Calendar>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
57
src/stories/components/Text.stories.tsx
Normal file
57
src/stories/components/Text.stories.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Button } from 'src/views/components/common/Button/Button';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import Text from '../../views/components/common/Text/Text';
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
|
||||
const meta = {
|
||||
title: 'Components/Common/Text',
|
||||
component: Text,
|
||||
parameters: {
|
||||
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
||||
layout: 'centered',
|
||||
},
|
||||
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
||||
tags: ['autodocs'],
|
||||
// More on argTypes: https://storybook.js.org/docs/api/argtypes
|
||||
args: {
|
||||
children: 'The quick brown fox jumps over the lazy dog.',
|
||||
},
|
||||
argTypes: {
|
||||
children: { control: 'text' },
|
||||
},
|
||||
} satisfies Meta<typeof Text>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
};
|
||||
|
||||
export const AllVariants: Story = {
|
||||
args: {
|
||||
children: 'The quick brown fox jumps over the lazy dog.',
|
||||
},
|
||||
render: props => (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
||||
<Text {...props} variant='mini' />
|
||||
<Text {...props} variant='small' />
|
||||
<Text {...props} variant='p' />
|
||||
<Text {...props} variant='h4' />
|
||||
<Text {...props} variant='h3-course' />
|
||||
<Text {...props} variant='h3' />
|
||||
<Text {...props} variant='h2-course' />
|
||||
<Text {...props} variant='h2' />
|
||||
<Text {...props} variant='h1-course' />
|
||||
<Text {...props} variant='h1' />
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
design: {
|
||||
type: 'figma',
|
||||
url: 'https://www.figma.com/file/8tsCay2FRqctrdcZ3r9Ahw/UTRP?type=design&node-id=324-389&mode=design&t=BoS5xBrpSsjgQXqv-4',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -9,7 +9,7 @@
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease-in-out;
|
||||
font-family: 'Roboto';
|
||||
font-family: 'Roboto Flex';
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
@use 'sass:color';
|
||||
@use 'src/views/styles/colors.module.scss';
|
||||
|
||||
.dayLabelContainer {
|
||||
display: flex;
|
||||
height: 13px;
|
||||
min-width: 40px;
|
||||
min-height: 13px;
|
||||
padding-bottom: 15px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex: 1 0 0;
|
||||
}
|
||||
|
||||
.dayLabel {
|
||||
color: colors.$burnt_orange;
|
||||
text-align: center;
|
||||
font-family: Roboto;
|
||||
font-size: 14.22px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
display: grid;
|
||||
grid-template-columns: auto repeat(5, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.day {
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.timeBlock {
|
||||
display: flex;
|
||||
width: 50px;
|
||||
height: 40.279px;
|
||||
min-width: 50px;
|
||||
max-width: 50px;
|
||||
min-height: 40px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.timeLabelContainer {
|
||||
display: flex;
|
||||
max-height: 20px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
gap: 17px;
|
||||
flex: 1 0 0;
|
||||
align-self: stretch;
|
||||
border-radius: var(--border-radius-none, 0px);
|
||||
}
|
||||
37
src/views/components/common/CalendarGrid/CalendarGrid.tsx
Normal file
37
src/views/components/common/CalendarGrid/CalendarGrid.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import styles from './CalendarGrid.module.scss';
|
||||
import CalendarCell from '../CalendarGridCell/CalendarGridCell';
|
||||
import { DAY_MAP } from 'src/shared/types/CourseMeeting';
|
||||
|
||||
const daysOfWeek = Object.values(DAY_MAP);
|
||||
const hoursOfDay = Array.from({ length: 14 }, (_, index) => index + 8);
|
||||
|
||||
/**
|
||||
* Grid of CalendarGridCell components forming the user's course schedule calendar view
|
||||
* @param props
|
||||
*/
|
||||
const Calendar: React.FC = (props) => {
|
||||
|
||||
return (
|
||||
<div className={styles.calendar}>
|
||||
<div className={styles.dayLabelContainer}></div>
|
||||
{daysOfWeek.map((day, dayIndex) => (
|
||||
<div key={dayIndex} className={styles.day}>
|
||||
<div className={styles.dayLabelContainer}>
|
||||
<div className={styles.dayLabel}>{day}</div>
|
||||
</div>
|
||||
{hoursOfDay.map((hour) => (
|
||||
<div key={`${day}-${hour}`} className={styles.timeBlock}>
|
||||
<div className={styles.timeLabelContainer}>
|
||||
<span>{hour}:00</span>
|
||||
</div>
|
||||
<CalendarCell />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Calendar;
|
||||
@@ -0,0 +1,20 @@
|
||||
.calendarCell {
|
||||
display: flex;
|
||||
width: 165px;
|
||||
height: 52.231px;
|
||||
min-width: 45px;
|
||||
min-height: 40px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hourLine {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
border-top: 1px solid black; /* Adjust line styles as needed */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import styles from './CalendarGridCell.module.scss';
|
||||
|
||||
/**
|
||||
* Component representing each 1 hour time block of a calendar
|
||||
* @param props
|
||||
*/
|
||||
const CalendarCell: React.FC = (props) => {
|
||||
return (
|
||||
<div className={styles.calendarCell}>
|
||||
<div className={styles.hourLine}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CalendarCell;
|
||||
@@ -2,59 +2,64 @@
|
||||
@use 'src/views/styles/fonts.module.scss';
|
||||
|
||||
.text {
|
||||
font-family: 'Inter', sans-serif;
|
||||
color: colors.$charcoal;
|
||||
line-height: initial;
|
||||
font-family: 'Roboto Flex', sans-serif;
|
||||
line-height: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.light_weight {
|
||||
font-weight: fonts.$light_weight;
|
||||
.mini {
|
||||
font-size: 0.79rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.regular_weight {
|
||||
font-weight: fonts.$regular_weight;
|
||||
.small {
|
||||
font-size: 0.88875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.normal_weight {
|
||||
font-weight: fonts.$normal_weight;
|
||||
.p {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.025rem;
|
||||
}
|
||||
|
||||
.semi_bold_weight {
|
||||
font-weight: fonts.$semi_bold_weight;
|
||||
.h4 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bold_weight {
|
||||
font-weight: fonts.$bold_weight;
|
||||
.h3-course {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 400;
|
||||
line-height: 100%; /* 0.6875rem */
|
||||
}
|
||||
|
||||
.black_weight {
|
||||
font-weight: fonts.$black_weight;
|
||||
.h3 {
|
||||
font-size: 1.26563rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.x_small_size {
|
||||
font-size: fonts.$x_small_size;
|
||||
.h2-course {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.03125rem;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.xx_small_size {
|
||||
font-size: fonts.$xx_small_size;
|
||||
.h2 {
|
||||
font-size: 1.42375rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.small_size {
|
||||
font-size: fonts.$small_size;
|
||||
.h1-course {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.medium_size {
|
||||
font-size: fonts.$medium_size;
|
||||
}
|
||||
|
||||
.large_size {
|
||||
font-size: fonts.$large_size;
|
||||
}
|
||||
|
||||
.x_large_size {
|
||||
font-size: fonts.$x_large_size;
|
||||
}
|
||||
|
||||
.xx_large_size {
|
||||
font-size: fonts.$xx_large_size;
|
||||
.h1 {
|
||||
font-size: 1.60188rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -1,50 +1,32 @@
|
||||
import classNames from 'classnames';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import colors, { Color } from '@views/styles/colors.module.scss';
|
||||
import { Size, Weight } from '@views/styles/fonts.module.scss';
|
||||
import styles from './Text.module.scss';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export type TextProps = {
|
||||
color?: Color;
|
||||
weight?: Weight;
|
||||
size?: Size;
|
||||
span?: boolean;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
align?: React.CSSProperties['textAlign'];
|
||||
style?: React.CSSProperties;
|
||||
};
|
||||
variant?: Variant;
|
||||
} & (
|
||||
| (React.HTMLAttributes<HTMLSpanElement> & { as?: 'span' })
|
||||
| (React.HTMLAttributes<HTMLDivElement> & { as: 'div' })
|
||||
);
|
||||
|
||||
const variants = ['mini', 'small', 'p', 'h4', 'h3-course', 'h3', 'h2-course', 'h2', 'h1-course', 'h1'] as const;
|
||||
|
||||
type Variant = (typeof variants)[number];
|
||||
|
||||
/**
|
||||
* A reusable Text component with props that build on top of the design system for the extension
|
||||
*/
|
||||
export default function Text(props: PropsWithChildren<TextProps>) {
|
||||
const style: React.CSSProperties = {
|
||||
...props.style,
|
||||
textAlign: props.align,
|
||||
color: props.color ? colors[props.color] : undefined,
|
||||
};
|
||||
export default function Text({ variant, as, className, ...props }: PropsWithChildren<TextProps>) {
|
||||
const mergedClassName = classNames(styles.text, styles[variant], className);
|
||||
|
||||
const weightClass = `${props.weight ?? 'regular'}_weight`;
|
||||
const fontSizeClass = `${props.size ?? 'medium'}_size`;
|
||||
|
||||
const className = classNames(styles.text, styles[weightClass], styles[fontSizeClass], props.className);
|
||||
|
||||
if (props.span) {
|
||||
return (
|
||||
<span title={props.title} className={className} style={style} onClick={props.onClick}>
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (as === 'div') return <div className={mergedClassName} {...props} />;
|
||||
|
||||
return (
|
||||
<div title={props.title} className={className} style={style} onClick={props.onClick}>
|
||||
<span className={mergedClassName} {...props}>
|
||||
{props.children}
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
@each $weight in '100' '300' '400' '500' '700' '900' {
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('@public/fonts/roboto-#{$weight}.woff2') format('woff2');
|
||||
font-display: auto;
|
||||
font-style: normal;
|
||||
font-weight: #{$weight};
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto Flex';
|
||||
src: url('@public/fonts/roboto-flex.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -26,34 +23,12 @@
|
||||
src: url('@public/fonts/material-icons.woff2') format('woff2');
|
||||
}
|
||||
|
||||
$light_weight: 300;
|
||||
$regular_weight: 400;
|
||||
$normal_weight: 500;
|
||||
$semi_bold_weight: 600;
|
||||
$bold_weight: 700;
|
||||
$black_weight: 900;
|
||||
$normal_weight: 500; // Used by <Icon>, will be removed later
|
||||
|
||||
$xx_small_size: 4px;
|
||||
$x_small_size: 8px;
|
||||
$small_size: 12px;
|
||||
$medium_size: 16px;
|
||||
$large_size: 20px;
|
||||
$x_large_size: 32px;
|
||||
$xx_large_size: 48px;
|
||||
|
||||
:export {
|
||||
light_weight: $light_weight;
|
||||
regular_weight: $regular_weight;
|
||||
normal_weight: $normal_weight;
|
||||
semi_bold_weight: $semi_bold_weight;
|
||||
bold_weight: $bold_weight;
|
||||
black_weight: $black_weight;
|
||||
|
||||
xx_small_size: $xx_small_size;
|
||||
x_small_size: $x_small_size;
|
||||
small_size: $small_size;
|
||||
medium_size: $medium_size;
|
||||
large_size: $large_size;
|
||||
x_large_size: $x_large_size;
|
||||
xx_large_size: $xx_large_size;
|
||||
}
|
||||
|
||||
11
src/views/styles/fonts.module.scss.d.ts
vendored
11
src/views/styles/fonts.module.scss.d.ts
vendored
@@ -2,25 +2,14 @@
|
||||
* the type for all the weight scss variables exported from fonts.module.scss
|
||||
*/
|
||||
export interface IWeights {
|
||||
light_weight: number;
|
||||
regular_weight: number;
|
||||
normal_weight: number;
|
||||
bold_weight: number;
|
||||
semi_bold_weight: number;
|
||||
black_weight: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* the type for all the size scss variables exported from fonts.module.scss
|
||||
*/
|
||||
export interface ISizes {
|
||||
xx_small_size: number;
|
||||
x_small_size: number;
|
||||
small_size: number;
|
||||
medium_size: number;
|
||||
large_size: number;
|
||||
x_large_size: number;
|
||||
xx_large_size: number;
|
||||
}
|
||||
|
||||
/** A utility type that removes the _weight postfix from the variable names for weights */
|
||||
|
||||
Reference in New Issue
Block a user