timetable-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 1d209e5c04b5f8031e00cdaff3f8880a320cd052
parent 26f66d9f223b54e1c35973acc2c4ef407ec72ae7
Author: Yuukin256 <52195426+Yuukin256@users.noreply.github.com>
Date:   Sun,  5 May 2024 19:58:11 +0900

CIを設定 (#62)

* GitHub Actions で ESLint, Prettier, 型チェックを設定

* フォーマットを実行
Diffstat:
A.github/workflows/ci.yml | 48++++++++++++++++++++++++++++++++++++++++++++++++
M.lintstagedrc.yml | 2+-
Mnext.config.js | 2+-
Msrc/client/components/IconButtonDatePicker/index.tsx | 2+-
Msrc/client/components/Link/index.tsx | 119++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/client/features/daily/components/DatePicker.tsx | 2+-
Msrc/client/features/daily/hooks/useIndexAndDate.ts | 6+++---
Msrc/client/features/setting/components/MyClassForm.tsx | 2+-
Msrc/client/features/setting/components/ThemeSwitch.tsx | 2+-
Msrc/client/hooks/useMap.ts | 4++--
Msrc/client/hooks/useMyClass.ts | 4++--
Msrc/common/utils/formatDate.ts | 2+-
Msrc/pages/[class]/index.tsx | 8++++----
Msrc/pages/_app.tsx | 2+-
Msrc/server/context.ts | 2+-
Msrc/server/routers/dayPeriodSchedule.ts | 4++--
16 files changed, 130 insertions(+), 81 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: CI + +on: + - pull_request + +jobs: + lint-format-type: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Run ESLint + run: pnpm lint + + - name: Run Prettier + run: pnpm prettier . --check + + - name: Run type check + run: pnpm type-check diff --git a/.lintstagedrc.yml b/.lintstagedrc.yml @@ -1,2 +1,2 @@ '*.{js,ts,jsx,tsx}': ['npx eslint --fix'] -'*.{js,ts,jsx,tsx,json}': ['npx prettier --write'] +'*.{js,ts,jsx,tsx,json}': ['npx prettier . --write'] diff --git a/next.config.js b/next.config.js @@ -28,7 +28,7 @@ const nextConfig = withPWA({ destination: '/' + className, permanent: false, }; - }) + }), ); const startDefaultRedirect = { diff --git a/src/client/components/IconButtonDatePicker/index.tsx b/src/client/components/IconButtonDatePicker/index.tsx @@ -13,7 +13,7 @@ const NothingField = function NothingField() { }; export default memo(function IconButtonDatePicker( - props: Omit<MobileDatePickerProps<Date>, 'open' | 'onOpen' | 'onClose'> + props: Omit<MobileDatePickerProps<Date>, 'open' | 'onOpen' | 'onClose'>, ) { const ref = useRef<HTMLButtonElement | null>(null); const [open, handlers] = useDisclosure(false); diff --git a/src/client/components/Link/index.tsx b/src/client/components/Link/index.tsx @@ -65,78 +65,79 @@ export type LinkProps = { // A styled version of the Next.js Link component: // https://nextjs.org/docs/api-reference/next/link -const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link( - props, - ref -) { - const { - activeClassName = 'active', - as, - className: classNameProps, - href, - legacyBehavior, - linkAs: linkAsProp, - locale, - noLinkStyle, - prefetch, - replace, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - role, // Link don't have roles. - scroll, - shallow, - ...other - } = props; +const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( + function Link(props, ref) { + const { + activeClassName = 'active', + as, + className: classNameProps, + href, + legacyBehavior, + linkAs: linkAsProp, + locale, + noLinkStyle, + prefetch, + replace, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + role, // Link don't have roles. + scroll, + shallow, + ...other + } = props; - const router = useRouter(); - const pathname = typeof href === 'string' ? href : href.pathname; - const className = clsx(classNameProps, { - [activeClassName]: router.pathname === pathname && activeClassName, - }); + const router = useRouter(); + const pathname = typeof href === 'string' ? href : href.pathname; + const className = clsx(classNameProps, { + [activeClassName]: router.pathname === pathname && activeClassName, + }); - const isExternal = - typeof href === 'string' && - (href.indexOf('http') === 0 || href.indexOf('mailto:') === 0); + const isExternal = + typeof href === 'string' && + (href.indexOf('http') === 0 || href.indexOf('mailto:') === 0); - if (isExternal) { - if (noLinkStyle) { - return <Anchor className={className} href={href} ref={ref} {...other} />; + if (isExternal) { + if (noLinkStyle) { + return ( + <Anchor className={className} href={href} ref={ref} {...other} /> + ); + } + + return <MuiLink className={className} href={href} ref={ref} {...other} />; } - return <MuiLink className={className} href={href} ref={ref} {...other} />; - } + const linkAs = linkAsProp || as; + const nextjsProps = { + to: href, + linkAs, + replace, + scroll, + shallow, + prefetch, + legacyBehavior, + locale, + }; - const linkAs = linkAsProp || as; - const nextjsProps = { - to: href, - linkAs, - replace, - scroll, - shallow, - prefetch, - legacyBehavior, - locale, - }; + if (noLinkStyle) { + return ( + <NextLinkComposed + className={className} + ref={ref} + {...nextjsProps} + {...other} + /> + ); + } - if (noLinkStyle) { return ( - <NextLinkComposed + <MuiLink + component={NextLinkComposed} className={className} ref={ref} {...nextjsProps} {...other} /> ); - } - - return ( - <MuiLink - component={NextLinkComposed} - className={className} - ref={ref} - {...nextjsProps} - {...other} - /> - ); -}); + }, +); export default Link; diff --git a/src/client/features/daily/components/DatePicker.tsx b/src/client/features/daily/components/DatePicker.tsx @@ -34,7 +34,7 @@ export default function DatePickerWithSideButton({ const maxDate = dates[dates.length - 1]; const shouldDisableDate = useCallback( (d1: Date) => dates.every((d2) => !isSameDay(d1, d2)), - [dates] + [dates], ); const canSelectToday = !shouldDisableDate(new Date()); diff --git a/src/client/features/daily/hooks/useIndexAndDate.ts b/src/client/features/daily/hooks/useIndexAndDate.ts @@ -18,7 +18,7 @@ const useIndexAndDate = (dateStrings: string[]): Return => { const size = dateStrings.length; const dates = useMemo( () => dateStrings.map((v) => new Date(v)), - [dateStrings] + [dateStrings], ); // 初期設定の日付: 16時以前なら当日; 16時以降なら翌日; その日の時間割がなければ最も近い未来の日付; 未来がなければ最も新しい日付 @@ -54,7 +54,7 @@ const useIndexAndDate = (dateStrings: string[]): Return => { const dateString = dateStrings[index]; const date = useMemo( () => (dateString ? new Date(dateString) : null), - [dateString] + [dateString], ); const setDate = useCallback( @@ -64,7 +64,7 @@ const useIndexAndDate = (dateStrings: string[]): Return => { setIndex(newIndex); } }, - [dateStrings] + [dateStrings], ); return { diff --git a/src/client/features/setting/components/MyClassForm.tsx b/src/client/features/setting/components/MyClassForm.tsx @@ -47,7 +47,7 @@ export default function MyClassForm() { }); } }, - [enqueueSnackbar, removeCookieValue, setCookieValue] + [enqueueSnackbar, removeCookieValue, setCookieValue], ); return ( diff --git a/src/client/features/setting/components/ThemeSwitch.tsx b/src/client/features/setting/components/ThemeSwitch.tsx @@ -19,7 +19,7 @@ export default function ThemeSwitch() { setMode(newMode); } }, - [setMode] + [setMode], ); return ( diff --git a/src/client/hooks/useMap.ts b/src/client/hooks/useMap.ts @@ -11,11 +11,11 @@ export interface Actions<K, V> { type Return<K, V> = [ Omit<Map<K, V>, 'set' | 'clear' | 'delete'>, - Actions<K, V> + Actions<K, V>, ]; function useMap<K, V>( - initialState: MapOrEntries<K, V> = new Map() + initialState: MapOrEntries<K, V> = new Map(), ): Return<K, V> { const [map, setMap] = useState(new Map(initialState)); diff --git a/src/client/hooks/useMyClass.ts b/src/client/hooks/useMyClass.ts @@ -31,11 +31,11 @@ const useMyClass = (): Return => { (update: GradeClass) => { setCookie(DEFAULT_CLASS_COOKIE_KEY, update, { expires }); }, - [expires, setCookie] + [expires, setCookie], ); const removeValue = useCallback( () => removeCookie(DEFAULT_CLASS_COOKIE_KEY), - [removeCookie] + [removeCookie], ); if (gradeClassValidation.success) { diff --git a/src/common/utils/formatDate.ts b/src/common/utils/formatDate.ts @@ -6,7 +6,7 @@ import { DATE_FORMAT } from 'common/constant'; const formatDate = ( date: Parameters<typeof format>[0], formatStr: string = DATE_FORMAT, - options?: Parameters<typeof format>[2] + options?: Parameters<typeof format>[2], ) => { return format(date, formatStr, { locale: ja, ...options }); }; diff --git a/src/pages/[class]/index.tsx b/src/pages/[class]/index.tsx @@ -26,7 +26,7 @@ type PageProps = { export const getStaticPaths: GetStaticPaths<UrlQuery> = async () => { const paths = GRADES.flatMap((g) => - CLASSES.map((c) => ({ params: { class: `${g}-${c}` } })) + CLASSES.map((c) => ({ params: { class: `${g}-${c}` } })), ); return { @@ -80,7 +80,7 @@ export const getStaticProps: GetStaticProps<PageProps, UrlQuery> = async ({ /** 曜日時限からクラスの科目データを返す */ const makeOnePeriodData = ( - dayPeriod?: DayPeriodJa + dayPeriod?: DayPeriodJa, ): OnePeriod | undefined => { if (dayPeriod) { return { @@ -109,12 +109,12 @@ export const getStaticProps: GetStaticProps<PageProps, UrlQuery> = async ({ period7: makeOnePeriodData(sch.period7), }, ]; - } + }, ); // 日付順に並び替える const sorted = dayTimetableCalendar.toSorted(([, a], [, b]) => - compareAsc(a.date, b.date) + compareAsc(a.date, b.date), ); return { diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx @@ -31,7 +31,7 @@ const StyledMaterialDesignContent = styled(MaterialDesignContent)( '&.notistack-MuiContent-warning': { backgroundColor: theme.vars.palette.warning.main, }, - }) + }), ); interface MyAppProps extends AppProps<{ children: ReactNode }> { diff --git a/src/server/context.ts b/src/server/context.ts @@ -6,7 +6,7 @@ import type * as trpcNext from '@trpc/server/adapters/next'; // create context based of incoming request // set as optional here so it can also be re-used for `getStaticProps()` export const createContext = async ( - opts?: trpcNext.CreateNextContextOptions + opts?: trpcNext.CreateNextContextOptions, ) => { return { req: opts?.req, diff --git a/src/server/routers/dayPeriodSchedule.ts b/src/server/routers/dayPeriodSchedule.ts @@ -17,13 +17,13 @@ export const dayPeriodScheduleRouter = router({ grade: zodGrade, startDate: z.string(), endDate: z.string(), - }) + }), ) .query<[string, DayScheduleWithDate][]>(async ({ input }) => { const schedules = Object.entries(dayPeriodSchedules) .filter( ([date]) => - isAfter(date, input.startDate) && isBefore(date, input.endDate) + isAfter(date, input.startDate) && isBefore(date, input.endDate), ) .map(([date, allGradesSchedule]): [string, DayScheduleWithDate] => { const schedule = { ...allGradesSchedule[`grade${input.grade}`] };