index.tsx (4221B)
1 /** @jsxImportSource @emotion/react */ 2 import { useIsomorphicEffect } from '@mantine/hooks'; 3 import { GlobalStyles, Link, Alert as MUIAlert } from '@mui/material'; 4 import { css, styled } from '@mui/material/styles'; 5 import shuffle from 'lodash/shuffle'; 6 import { useState } from 'react'; 7 import { Autoplay, Pagination } from 'swiper/modules'; 8 import { Swiper, SwiperSlide } from 'swiper/react'; 9 import 'swiper/css'; 10 import 'swiper/css/autoplay'; 11 import 'swiper/css/pagination'; 12 13 import { BUG_REPORT_FORM_URL, FEEDBACK_FORM_URL } from 'common/constant'; 14 15 import type { AlertProps } from '@mui/material/Alert'; 16 import type { ReactNode } from 'react'; 17 18 const Alert = styled(MUIAlert)({ 19 height: '100%', 20 paddingBottom: '22px', // ページネーション用の余白 21 borderRadius: 0, 22 verticalAlign: 'center', 23 }); 24 25 const globalStyles = ( 26 <GlobalStyles 27 styles={(theme) => css` 28 .swiper .swiper-slide { 29 height: auto; 30 } 31 .swiper .swiper-pagination-bullet { 32 background-color: ${theme.vars.palette.text.primary}; 33 opacity: 0.3; 34 } 35 .swiper .swiper-pagination-bullet-active { 36 background-color: ${theme.vars.palette.primary.main}; 37 opacity: 1; 38 } 39 `} 40 /> 41 ); 42 43 type SlideData = { 44 id: number; 45 content: ReactNode; 46 severity?: AlertProps['severity']; 47 variant?: AlertProps['variant']; 48 icon?: AlertProps['icon']; 49 }; 50 51 const prioritySlideData: SlideData[] = [ 52 { 53 id: 11, 54 content: ( 55 <> 56 情報の正確性を保証することはできませんので、参考程度にお使いください。時間割が間違っていた場合、学校・IT部は一切の責任を負いません。 57 </> 58 ), 59 severity: 'warning', 60 }, 61 { 62 id: 12, 63 content: ( 64 <>臨時変更には対応していません。教室掲示のプリントで確認してください。</> 65 ), 66 severity: 'warning', 67 }, 68 { 69 id: 13, 70 content: ( 71 <> 72 臨時変更の情報を入力する機能を追加しました!登録した臨時変更情報は他の利用者に共有されません。ご要望ありがとうございました。 73 </> 74 ), 75 }, 76 ]; 77 78 const extraSlideData: SlideData[] = [ 79 { 80 id: 101, 81 content: ( 82 <> 83 このアプリはIT部が制作・運営しています。人手不足なので助けてください。 84 プログラミング経験者や開発に興味がある人はIT部まで! 85 </> 86 ), 87 }, 88 { 89 id: 102, 90 content: ( 91 <> 92 IT部 93 部員募集中!ボカロ楽曲制作、プログラミング、動画制作などやってます。 94 毎週木・金曜日にLAN教室までお気軽にお越しください! 95 </> 96 ), 97 }, 98 { 99 id: 103, 100 content: ( 101 <> 102 <Link href={FEEDBACK_FORM_URL} target='_blank' rel='noopener'> 103 フィードバックアンケート 104 </Link> 105 で、このアプリの評価にご協力お願いします。ご意見・ご要望もお待ちしております。 106 </> 107 ), 108 }, 109 { 110 id: 104, 111 content: ( 112 <> 113 アプリの不具合や時間割情報の誤りを見つけた場合は、 114 <Link href={BUG_REPORT_FORM_URL} target='_blank' rel='noopener'> 115 Googleフォーム 116 </Link> 117 で報告お願いします。 118 </> 119 ), 120 }, 121 // { 122 // id: 105, 123 // content: ( 124 // <> 125 // 広告募集中!ここに文字広告を載せられます。木・金曜日にLAN教室にお越しになるか、お近くのIT部員にお声がけください。 126 // </> 127 // ), 128 // }, 129 { 130 id: 106, 131 content: ( 132 <> 133 各時限の時間割をタップすると、授業場所、臨時変更入力機能、メモ機能などが表示されます。 134 </> 135 ), 136 }, 137 ]; 138 139 export default function SlideFooter() { 140 const [slideData, setSlideData] = useState([...prioritySlideData]); 141 useIsomorphicEffect( 142 () => setSlideData([...prioritySlideData, ...shuffle(extraSlideData)]), 143 [], 144 ); 145 146 return ( 147 <Swiper 148 modules={[Autoplay, Pagination]} 149 autoplay={{ delay: 5000 }} 150 pagination={{ clickable: true }} 151 allowTouchMove={false} 152 loop 153 > 154 {globalStyles} 155 {slideData.map((data) => ( 156 <SwiperSlide key={data.id}> 157 <Alert 158 severity={data.severity ?? 'info'} 159 variant={data.variant ?? 'standard'} 160 > 161 {data.content} 162 </Alert> 163 </SwiperSlide> 164 ))} 165 </Swiper> 166 ); 167 }