Ringtone app
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

163 行
3.4 KiB

  1. import {FC, FormEventHandler} from 'react';
  2. import styled from 'styled-components';
  3. import { LeftSidebarWithMenu } from '@theoryofnekomata/viewfinder'
  4. import Link from '../../molecules/navigation/Link';
  5. import {Session} from '@auth0/nextjs-auth0';
  6. import {models} from '@tonality/library-common';
  7. import RingtoneCardDisplay from '../../organisms/presentation/RingtoneCardDisplay';
  8. import Card from '../../molecules/presentation/Card';
  9. import ActionButton from '../../molecules/forms/ActionButton';
  10. import NumericInput from '../../molecules/forms/NumericInput';
  11. import BasicLayout from '../../organisms/presentation/BasicLayout';
  12. const CardList = styled('div')({
  13. display: 'grid',
  14. gap: '1rem',
  15. margin: '2rem 0',
  16. '@media (min-width: 720px)': {
  17. gridTemplateColumns: 'repeat(2, 1fr)',
  18. },
  19. })
  20. const CardLink = styled(Link)({
  21. display: 'block',
  22. textDecoration: 'none',
  23. })
  24. const StyledCard = styled(Card)({
  25. height: '100%',
  26. })
  27. const Footer = styled('div')({
  28. display: 'grid',
  29. gap: '1rem',
  30. gridTemplateColumns: '1fr',
  31. margin: '2rem 0',
  32. '@media (min-width: 720px)': {
  33. gridTemplateColumns: 'auto 1fr auto',
  34. },
  35. })
  36. const TakeForm = styled('form')({
  37. display: 'grid',
  38. gap: '1rem',
  39. gridTemplateColumns: '1fr auto',
  40. })
  41. const BrowseArea = styled('div')({
  42. '@media (min-width: 720px)': {
  43. gridColumn: 3,
  44. },
  45. })
  46. const TakeInput = styled(NumericInput)({
  47. '@media (min-width: 720px)': {
  48. width: '6rem',
  49. },
  50. })
  51. type Props = {
  52. onSearch?: FormEventHandler,
  53. onNextPage?: FormEventHandler,
  54. session?: Partial<Session>,
  55. ringtones: models.Ringtone[],
  56. skip?: number,
  57. take?: number,
  58. total?: number,
  59. loading?: boolean,
  60. }
  61. const BrowseRingtonesTemplate: FC<Props> = ({
  62. onSearch,
  63. session,
  64. ringtones,
  65. skip = 0,
  66. take = 10,
  67. total = 0,
  68. onNextPage,
  69. loading,
  70. }) => {
  71. return (
  72. <BasicLayout
  73. onSearch={onSearch}
  74. session={session}
  75. >
  76. <LeftSidebarWithMenu.ContentContainer>
  77. {
  78. Array.isArray(ringtones)
  79. && (
  80. <>
  81. <CardList>
  82. {ringtones.map(r => (
  83. <CardLink
  84. key={r.id.toString()}
  85. href={{
  86. pathname: '/ringtones/[id]',
  87. query: {
  88. id: r.id.toString(),
  89. },
  90. }}
  91. >
  92. <StyledCard>
  93. <RingtoneCardDisplay
  94. name={r.name}
  95. data={r.data}
  96. createdAt={r.createdAt}
  97. />
  98. </StyledCard>
  99. </CardLink>
  100. ))}
  101. </CardList>
  102. <Footer>
  103. <TakeForm>
  104. <TakeInput
  105. label="Visible Items"
  106. name="take"
  107. defaultValue={take}
  108. />
  109. <ActionButton
  110. type="submit"
  111. disabled={loading}
  112. >
  113. Set
  114. </ActionButton>
  115. </TakeForm>
  116. <BrowseArea>
  117. {
  118. skip + take < total
  119. && (
  120. <form
  121. onSubmit={onNextPage}
  122. >
  123. <input
  124. type="hidden"
  125. name="skip"
  126. value={skip + take}
  127. />
  128. <input
  129. type="hidden"
  130. name="take"
  131. value={take}
  132. />
  133. <ActionButton
  134. type="submit"
  135. disabled={loading}
  136. block
  137. >
  138. Browse More
  139. </ActionButton>
  140. </form>
  141. )
  142. }
  143. </BrowseArea>
  144. </Footer>
  145. </>
  146. )
  147. }
  148. </LeftSidebarWithMenu.ContentContainer>
  149. </BasicLayout>
  150. )
  151. }
  152. export default BrowseRingtonesTemplate