@coldsurf/ocean-road 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css/global.css +30 -0
- package/dist/index.d.ts +641 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +733 -0
- package/dist/index.js.map +1 -0
- package/dist/native.cjs +94 -0
- package/dist/native.cjs.map +1 -0
- package/dist/native.d.cts +304 -0
- package/dist/native.d.cts.map +1 -0
- package/dist/native.d.ts +304 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +94 -0
- package/dist/native.js.map +1 -0
- package/dist/next.cjs +949 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +270 -0
- package/dist/next.d.cts.map +1 -0
- package/dist/next.d.ts +270 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +949 -0
- package/dist/next.js.map +1 -0
- package/native/index.d.ts +7 -0
- package/next/index.d.ts +7 -0
- package/package.json +126 -0
- package/src/GlobalStyle.tsx +111 -0
- package/src/base/badge/badge.tsx +50 -0
- package/src/base/badge/index.ts +1 -0
- package/src/base/button/button.styled.tsx +123 -0
- package/src/base/button/button.tsx +60 -0
- package/src/base/button/button.types.ts +20 -0
- package/src/base/button/button.utils.ts +36 -0
- package/src/base/button/index.tsx +2 -0
- package/src/base/checkbox/checkbox.styled.ts +52 -0
- package/src/base/checkbox/checkbox.tsx +26 -0
- package/src/base/checkbox/index.ts +1 -0
- package/src/base/icon-button/icon-button.styled.ts +8 -0
- package/src/base/icon-button/icon-button.tsx +15 -0
- package/src/base/icon-button/icon-button.types.ts +3 -0
- package/src/base/icon-button/index.ts +2 -0
- package/src/base/index.ts +11 -0
- package/src/base/label/index.ts +1 -0
- package/src/base/label/label.styled.ts +7 -0
- package/src/base/label/label.tsx +27 -0
- package/src/base/modal/index.ts +1 -0
- package/src/base/modal/modal.tsx +59 -0
- package/src/base/spinner/index.ts +2 -0
- package/src/base/spinner/spinner.styled.ts +25 -0
- package/src/base/spinner/spinner.tsx +36 -0
- package/src/base/spinner/spinner.types.ts +1 -0
- package/src/base/switch/index.ts +1 -0
- package/src/base/switch/switch.styled.tsx +49 -0
- package/src/base/switch/switch.tsx +29 -0
- package/src/base/text/index.ts +1 -0
- package/src/base/text/text.styled.ts +17 -0
- package/src/base/text/text.tsx +37 -0
- package/src/base/text-area/index.ts +2 -0
- package/src/base/text-area/text-area.styled.ts +16 -0
- package/src/base/text-area/text-area.tsx +29 -0
- package/src/base/text-area/text-area.types.ts +11 -0
- package/src/base/text-input/index.ts +2 -0
- package/src/base/text-input/text-input.styled.ts +40 -0
- package/src/base/text-input/text-input.tsx +59 -0
- package/src/base/text-input/text-input.types.ts +15 -0
- package/src/base/toast/index.ts +2 -0
- package/src/base/toast/toast.tsx +60 -0
- package/src/base/toast/toast.types.ts +5 -0
- package/src/constants.ts +1 -0
- package/src/contexts/ColorSchemeProvider.tsx +154 -0
- package/src/css/global.css +30 -0
- package/src/extensions/accordion/accordion.hooks.ts +11 -0
- package/src/extensions/accordion/accordion.tsx +80 -0
- package/src/extensions/accordion/index.ts +1 -0
- package/src/extensions/app-header/app-header.hooks.ts +94 -0
- package/src/extensions/app-header/app-header.tsx +31 -0
- package/src/extensions/app-header/app-header.types.ts +1 -0
- package/src/extensions/app-header/index.ts +8 -0
- package/src/extensions/app-logo/app-logo.tsx +40 -0
- package/src/extensions/app-logo/index.ts +1 -0
- package/src/extensions/app-store-button/app-store-button.tsx +64 -0
- package/src/extensions/app-store-button/index.ts +1 -0
- package/src/extensions/brand-icon/brand-icon.android.tsx +11 -0
- package/src/extensions/brand-icon/brand-icon.apple.tsx +11 -0
- package/src/extensions/brand-icon/brand-icon.google.tsx +11 -0
- package/src/extensions/brand-icon/brand-icon.tsx +22 -0
- package/src/extensions/brand-icon/index.ts +1 -0
- package/src/extensions/color-scheme-toggle/color-scheme-toggle.tsx +76 -0
- package/src/extensions/color-scheme-toggle/index.ts +1 -0
- package/src/extensions/dropdown/dropdown.menu-item.tsx +237 -0
- package/src/extensions/dropdown/dropdown.result-item.tsx +26 -0
- package/src/extensions/dropdown/dropdown.styled.tsx +48 -0
- package/src/extensions/dropdown/dropdown.trigger.tsx +72 -0
- package/src/extensions/dropdown/dropdown.tsx +222 -0
- package/src/extensions/dropdown/dropdown.types.ts +3 -0
- package/src/extensions/dropdown/dropdown.utils.ts +40 -0
- package/src/extensions/dropdown/index.ts +14 -0
- package/src/extensions/error-ui/index.ts +7 -0
- package/src/extensions/error-ui/network-error/index.ts +1 -0
- package/src/extensions/error-ui/network-error/network-error.styled.ts +16 -0
- package/src/extensions/error-ui/network-error/network-error.tsx +14 -0
- package/src/extensions/error-ui/unknown-error/index.ts +1 -0
- package/src/extensions/error-ui/unknown-error/unknown-error.styled.ts +16 -0
- package/src/extensions/error-ui/unknown-error/unknown-error.tsx +14 -0
- package/src/extensions/full-screen-modal/full-screen-modal.tsx +52 -0
- package/src/extensions/full-screen-modal/index.ts +1 -0
- package/src/extensions/grid-card-image/grid-card-image.tsx +11 -0
- package/src/extensions/grid-card-image/index.ts +1 -0
- package/src/extensions/grid-card-image-empty/grid-card-image-empty.tsx +11 -0
- package/src/extensions/grid-card-image-empty/index.ts +1 -0
- package/src/extensions/grid-card-item/grid-card-item.masonry.styled.tsx +95 -0
- package/src/extensions/grid-card-item/grid-card-item.masonry.tsx +63 -0
- package/src/extensions/grid-card-item/grid-card-item.styled.tsx +93 -0
- package/src/extensions/grid-card-item/grid-card-item.subscribe-btn-layout.tsx +30 -0
- package/src/extensions/grid-card-item/grid-card-item.tsx +81 -0
- package/src/extensions/grid-card-item/index.ts +2 -0
- package/src/extensions/grid-card-list/grid-card-list.masonry.styled.tsx +45 -0
- package/src/extensions/grid-card-list/grid-card-list.masonry.tsx +58 -0
- package/src/extensions/grid-card-list/grid-card-list.styled.tsx +40 -0
- package/src/extensions/grid-card-list/grid-card-list.tsx +59 -0
- package/src/extensions/grid-card-list/index.ts +2 -0
- package/src/extensions/grid-card-list-empty/grid-card-list-empty.tsx +38 -0
- package/src/extensions/grid-card-list-empty/index.ts +1 -0
- package/src/extensions/grid-card-list-load-more/grid-card-list-load-more.styled.tsx +15 -0
- package/src/extensions/grid-card-list-load-more/grid-card-list-load-more.tsx +43 -0
- package/src/extensions/grid-card-list-load-more/index.ts +1 -0
- package/src/extensions/index.ts +38 -0
- package/src/extensions/menu-item/index.ts +1 -0
- package/src/extensions/menu-item/menu-item.tsx +87 -0
- package/src/extensions/sns-icon/index.ts +1 -0
- package/src/extensions/sns-icon/sns-icon.facebook.tsx +11 -0
- package/src/extensions/sns-icon/sns-icon.instagram.tsx +11 -0
- package/src/extensions/sns-icon/sns-icon.tsx +24 -0
- package/src/extensions/sns-icon/sns-icon.x.tsx +11 -0
- package/src/extensions/sns-icon/sns-icon.youtube.tsx +11 -0
- package/src/index.ts +8 -0
- package/src/native/button/button.styled.tsx +99 -0
- package/src/native/button/button.tsx +42 -0
- package/src/native/button/index.ts +1 -0
- package/src/native/contexts/color-scheme-context/color-scheme-context.tsx +45 -0
- package/src/native/contexts/color-scheme-context/index.ts +1 -0
- package/src/native/contexts/index.ts +1 -0
- package/src/native/icon-button/icon-button.styled.ts +6 -0
- package/src/native/icon-button/icon-button.tsx +33 -0
- package/src/native/icon-button/icon-button.types.ts +14 -0
- package/src/native/icon-button/icon-button.utils.ts +114 -0
- package/src/native/icon-button/index.ts +1 -0
- package/src/native/index.ts +9 -0
- package/src/native/modal/index.ts +2 -0
- package/src/native/modal/modal.styled.ts +17 -0
- package/src/native/modal/modal.tsx +21 -0
- package/src/native/modal/modal.types.ts +8 -0
- package/src/native/profile-thumbnail/index.ts +1 -0
- package/src/native/profile-thumbnail/profile-thumbnail.tsx +91 -0
- package/src/native/spinner/index.ts +1 -0
- package/src/native/spinner/spinner.tsx +75 -0
- package/src/native/text/index.ts +2 -0
- package/src/native/text/text.tsx +51 -0
- package/src/native/text/text.types.ts +5 -0
- package/src/native/text-input/index.ts +2 -0
- package/src/native/text-input/text-input.tsx +72 -0
- package/src/native/text-input/text-input.types.ts +3 -0
- package/src/native/toast/index.ts +2 -0
- package/src/native/toast/toast.styled.ts +40 -0
- package/src/native/toast/toast.tsx +23 -0
- package/src/native/toast/toast.types.ts +10 -0
- package/src/next/app-footer/app-footer.tsx +250 -0
- package/src/next/app-footer/index.ts +1 -0
- package/src/next/app-header/app-header.fixed-header.tsx +83 -0
- package/src/next/app-header/app-header.full-screen-mobile-accordion-drawer.tsx +131 -0
- package/src/next/app-header/app-header.logo.tsx +50 -0
- package/src/next/app-header/app-header.modal-mobile-accordion-drawer.tsx +69 -0
- package/src/next/app-header/app-header.styled.ts +160 -0
- package/src/next/app-header/app-header.tsx +91 -0
- package/src/next/app-header/index.ts +13 -0
- package/src/next/global-link/global-link.store.ts +41 -0
- package/src/next/global-link/global-link.tsx +52 -0
- package/src/next/global-link/global-link.utils.ts +9 -0
- package/src/next/global-link/index.ts +3 -0
- package/src/next/grid-card-item/grid-card-item.masonry.tsx +23 -0
- package/src/next/grid-card-item/grid-card-item.tsx +23 -0
- package/src/next/grid-card-item/index.ts +2 -0
- package/src/next/index.ts +16 -0
- package/src/next/new-tab-link/index.ts +1 -0
- package/src/next/new-tab-link/new-tab-link.tsx +15 -0
- package/src/next/route-loading/index.ts +1 -0
- package/src/next/route-loading/route-loading.tsx +21 -0
- package/src/tokens/index.ts +2 -0
- package/src/tokens/tokens.ts +8 -0
- package/src/tokens/tokens.types.ts +7 -0
- package/src/utils/breakpoints.ts +9 -0
- package/src/utils/common-styles.ts +23 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/media.ts +23 -0
- package/src/utils/use-prevent-scroll-effect.ts +19 -0
- package/src/utils/with-id.ts +3 -0
- package/src/utils/with-stop-propagation.ts +10 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Button } from '@/base';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { StyledErrorContainer, StyledErrorText } from './network-error.styled';
|
|
4
|
+
|
|
5
|
+
export const NetworkError = memo(({ onClickRetry }: { onClickRetry: () => void }) => {
|
|
6
|
+
return (
|
|
7
|
+
<StyledErrorContainer>
|
|
8
|
+
<StyledErrorText as="h1">네트워크 에러가 발생했어요 🗯</StyledErrorText>
|
|
9
|
+
<Button onClick={onClickRetry}>다시 시도하기</Button>
|
|
10
|
+
</StyledErrorContainer>
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
NetworkError.displayName = 'ErrorUI.NetworkError';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './unknown-error';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Text } from '@/base';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
|
|
4
|
+
export const StyledErrorContainer = styled.div`
|
|
5
|
+
height: 100vh;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
export const StyledErrorText = styled(Text)`
|
|
13
|
+
font-weight: bold;
|
|
14
|
+
margin: unset;
|
|
15
|
+
margin-bottom: 1rem;
|
|
16
|
+
`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Button } from '@/base';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { StyledErrorContainer, StyledErrorText } from './unknown-error.styled';
|
|
4
|
+
|
|
5
|
+
export const UnknownError = memo(({ onClickRetry }: { onClickRetry: () => void }) => {
|
|
6
|
+
return (
|
|
7
|
+
<StyledErrorContainer>
|
|
8
|
+
<StyledErrorText as="h1">알 수 없는 오류가 발생했어요 🗯</StyledErrorText>
|
|
9
|
+
<Button onClick={onClickRetry}>다시 시도하기</Button>
|
|
10
|
+
</StyledErrorContainer>
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
UnknownError.displayName = 'ErrorUI.UnknownError';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Modal } from '@/base';
|
|
2
|
+
import { semantics } from '@/tokens';
|
|
3
|
+
import { usePreventScrollEffect } from '@/utils/use-prevent-scroll-effect';
|
|
4
|
+
import styled from '@emotion/styled';
|
|
5
|
+
import { XIcon } from 'lucide-react';
|
|
6
|
+
import { type PropsWithChildren, memo } from 'react';
|
|
7
|
+
|
|
8
|
+
const StyledFullScreenModalContent = styled.div`
|
|
9
|
+
position: fixed;
|
|
10
|
+
top: 0;
|
|
11
|
+
left: 0;
|
|
12
|
+
right: 0;
|
|
13
|
+
bottom: 0;
|
|
14
|
+
background: ${semantics.color.background[2]};
|
|
15
|
+
padding: 1rem;
|
|
16
|
+
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
|
|
20
|
+
overflow-y: auto;
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const CloseIcon = styled(XIcon)`
|
|
24
|
+
color: ${semantics.color.foreground[1]};
|
|
25
|
+
margin-left: auto;
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
type Props = PropsWithChildren<{
|
|
32
|
+
visible: boolean;
|
|
33
|
+
onClose: () => void;
|
|
34
|
+
zIndex?: number;
|
|
35
|
+
}>;
|
|
36
|
+
|
|
37
|
+
export const FullScreenModal = memo(({ visible, onClose, children, zIndex }: Props) => {
|
|
38
|
+
usePreventScrollEffect({
|
|
39
|
+
shouldPrevent: visible,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Modal visible={visible} onClose={onClose} zIndex={zIndex}>
|
|
44
|
+
<StyledFullScreenModalContent>
|
|
45
|
+
<CloseIcon onClick={onClose} />
|
|
46
|
+
{children}
|
|
47
|
+
</StyledFullScreenModalContent>
|
|
48
|
+
</Modal>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
FullScreenModal.displayName = 'FullScreenModal';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './full-screen-modal';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { semantics } from '@/tokens';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
|
|
4
|
+
export const GridCardImage = styled.img`
|
|
5
|
+
width: 100%;
|
|
6
|
+
aspect-ratio: 1 / 1;
|
|
7
|
+
object-fit: cover;
|
|
8
|
+
object-position: 50%;
|
|
9
|
+
border-radius: 12px;
|
|
10
|
+
background-color: ${semantics.color.background[3]};
|
|
11
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './grid-card-image';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { semantics } from '@/tokens';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
|
|
4
|
+
export const GridCardImageEmpty = styled.div`
|
|
5
|
+
width: 100%;
|
|
6
|
+
aspect-ratio: 1 / 1;
|
|
7
|
+
object-fit: cover;
|
|
8
|
+
object-position: 50%;
|
|
9
|
+
border-radius: 12px;
|
|
10
|
+
background-color: ${semantics.color.background[3]};
|
|
11
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './grid-card-image-empty';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Text } from '@/base';
|
|
2
|
+
import { semantics } from '@/tokens';
|
|
3
|
+
import { media } from '@/utils';
|
|
4
|
+
import { css } from '@emotion/react';
|
|
5
|
+
import styled from '@emotion/styled';
|
|
6
|
+
|
|
7
|
+
export const StyledGridDate = styled(Text)`
|
|
8
|
+
margin: unset;
|
|
9
|
+
margin-top: 0.25rem;
|
|
10
|
+
font-size: 20px;
|
|
11
|
+
font-weight: 500;
|
|
12
|
+
color: ${semantics.color.foreground[3]};
|
|
13
|
+
margin-bottom: 0.875rem;
|
|
14
|
+
|
|
15
|
+
${media.large(css`
|
|
16
|
+
font-size: 17.5px;
|
|
17
|
+
`)}
|
|
18
|
+
${media.small(css`
|
|
19
|
+
font-size: 14px;
|
|
20
|
+
`)}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
export const StyledGridImageEmptyContainer = styled.div`
|
|
24
|
+
width: 100%;
|
|
25
|
+
aspect-ratio: 1 / 1;
|
|
26
|
+
object-fit: cover;
|
|
27
|
+
object-position: 50%;
|
|
28
|
+
border-radius: 12px;
|
|
29
|
+
background-color: ${semantics.color.background[1]};
|
|
30
|
+
|
|
31
|
+
display: flex;
|
|
32
|
+
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
export const StyledGridImageEmptyText = styled(Text)`
|
|
38
|
+
text-align: center;
|
|
39
|
+
font-weight: 600;
|
|
40
|
+
font-size: 16px;
|
|
41
|
+
|
|
42
|
+
padding-left: 1rem;
|
|
43
|
+
padding-right: 1rem;
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
export const StyledGridItem = styled.div`
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
margin-bottom: 0.875rem;
|
|
50
|
+
|
|
51
|
+
${media.medium(css`
|
|
52
|
+
margin-bottom: 0.5rem;
|
|
53
|
+
`)}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export const StyledGridTop = styled.div`
|
|
57
|
+
position: relative;
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
export const StyledGridTextContainer = styled.div`
|
|
61
|
+
margin-top: 0.5rem;
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
export const StyledGridTitle = styled(Text)`
|
|
65
|
+
margin: unset;
|
|
66
|
+
font-size: 22px;
|
|
67
|
+
color: ${semantics.color.foreground[1]};
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
|
|
70
|
+
overflow-wrap: break-word;
|
|
71
|
+
word-wrap: break-word;
|
|
72
|
+
word-break: break-all;
|
|
73
|
+
|
|
74
|
+
${media.large(css`
|
|
75
|
+
font-size: 1.5rem;
|
|
76
|
+
font-size: 20px;
|
|
77
|
+
`)}
|
|
78
|
+
${media.small(css`
|
|
79
|
+
font-size: 1.25rem;
|
|
80
|
+
font-size: 16.5px;
|
|
81
|
+
`)}
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
export const StyledVenueText = styled(Text)`
|
|
85
|
+
margin: unset;
|
|
86
|
+
margin-top: 0.25rem;
|
|
87
|
+
font-size: 1.125rem;
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
color: ${semantics.color.foreground[4]};
|
|
90
|
+
text-align: right;
|
|
91
|
+
|
|
92
|
+
${media.small(css`
|
|
93
|
+
font-size: 14.5px;
|
|
94
|
+
`)}
|
|
95
|
+
`;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
import { match } from 'ts-pattern';
|
|
3
|
+
import { GridCardImage } from '../grid-card-image';
|
|
4
|
+
import type { GridCardListItemProps } from './grid-card-item';
|
|
5
|
+
import {
|
|
6
|
+
StyledGridDate,
|
|
7
|
+
StyledGridImageEmptyContainer,
|
|
8
|
+
StyledGridImageEmptyText,
|
|
9
|
+
StyledGridItem,
|
|
10
|
+
StyledGridTextContainer,
|
|
11
|
+
StyledGridTitle,
|
|
12
|
+
StyledGridTop,
|
|
13
|
+
StyledVenueText,
|
|
14
|
+
} from './grid-card-item.masonry.styled';
|
|
15
|
+
import { FixedSubscribeEventButtonLayout } from './grid-card-item.subscribe-btn-layout';
|
|
16
|
+
|
|
17
|
+
export const MasonryGridCardItem = memo(
|
|
18
|
+
({
|
|
19
|
+
isSubscribed,
|
|
20
|
+
thumbnailUrl,
|
|
21
|
+
titleText,
|
|
22
|
+
subText,
|
|
23
|
+
bottomText,
|
|
24
|
+
rightBottomSlot,
|
|
25
|
+
renderThumbnail,
|
|
26
|
+
}: GridCardListItemProps) => {
|
|
27
|
+
return (
|
|
28
|
+
<StyledGridItem>
|
|
29
|
+
<StyledGridTitle as="p">{titleText}</StyledGridTitle>
|
|
30
|
+
<StyledGridDate as="p">{subText}</StyledGridDate>
|
|
31
|
+
<StyledGridTop>
|
|
32
|
+
{thumbnailUrl ? (
|
|
33
|
+
renderThumbnail ? (
|
|
34
|
+
renderThumbnail(thumbnailUrl)
|
|
35
|
+
) : (
|
|
36
|
+
<GridCardImage src={thumbnailUrl} alt={titleText} />
|
|
37
|
+
)
|
|
38
|
+
) : (
|
|
39
|
+
<StyledGridImageEmptyContainer>
|
|
40
|
+
<StyledGridImageEmptyText>{titleText}</StyledGridImageEmptyText>
|
|
41
|
+
</StyledGridImageEmptyContainer>
|
|
42
|
+
)}
|
|
43
|
+
{match(rightBottomSlot)
|
|
44
|
+
.with(
|
|
45
|
+
{ type: 'subscribe' },
|
|
46
|
+
(value) =>
|
|
47
|
+
typeof isSubscribed === 'boolean' && (
|
|
48
|
+
<FixedSubscribeEventButtonLayout>
|
|
49
|
+
{value.subscribeEventBtn}
|
|
50
|
+
</FixedSubscribeEventButtonLayout>
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
.otherwise(() => null)}
|
|
54
|
+
</StyledGridTop>
|
|
55
|
+
<StyledGridTextContainer>
|
|
56
|
+
{bottomText && <StyledVenueText as="p">{bottomText}</StyledVenueText>}
|
|
57
|
+
</StyledGridTextContainer>
|
|
58
|
+
</StyledGridItem>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
MasonryGridCardItem.displayName = 'GridCardList.MasonryItem';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Text } from '@/base';
|
|
2
|
+
import { semantics } from '@/tokens';
|
|
3
|
+
import { media } from '@/utils';
|
|
4
|
+
import { css } from '@emotion/react';
|
|
5
|
+
import styled from '@emotion/styled';
|
|
6
|
+
import { motion } from 'framer-motion';
|
|
7
|
+
|
|
8
|
+
export const StyledGridItem = styled.div`
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
export const StyledGridTop = styled.div`
|
|
14
|
+
position: relative;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const StyledGridImageEmptyContainer = styled.div`
|
|
18
|
+
width: 100%;
|
|
19
|
+
aspect-ratio: 1 / 1;
|
|
20
|
+
object-fit: cover;
|
|
21
|
+
object-position: 50%;
|
|
22
|
+
border-radius: 12px;
|
|
23
|
+
background-color: ${semantics.color.background[1]};
|
|
24
|
+
|
|
25
|
+
display: flex;
|
|
26
|
+
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
export const StyledGridImageEmptyText = styled(Text)`
|
|
32
|
+
text-align: center;
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
font-size: 16px;
|
|
35
|
+
|
|
36
|
+
padding-left: 1rem;
|
|
37
|
+
padding-right: 1rem;
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
export const StyledGridTextContainer = styled.div`
|
|
41
|
+
margin-top: 0.5rem;
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
export const StyledGridTitle = styled(Text)`
|
|
45
|
+
margin: unset;
|
|
46
|
+
font-size: 16px;
|
|
47
|
+
color: ${semantics.color.foreground[1]};
|
|
48
|
+
font-weight: 600;
|
|
49
|
+
|
|
50
|
+
overflow-wrap: break-word;
|
|
51
|
+
word-wrap: break-word;
|
|
52
|
+
word-break: break-all;
|
|
53
|
+
|
|
54
|
+
${media.medium(css`
|
|
55
|
+
font-size: 14px;
|
|
56
|
+
`)}
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
export const StyledGridDate = styled(Text)`
|
|
60
|
+
margin: unset;
|
|
61
|
+
margin-top: 0.25rem;
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
color: ${semantics.color.foreground[3]};
|
|
64
|
+
|
|
65
|
+
${media.medium(css`
|
|
66
|
+
font-size: 12px;
|
|
67
|
+
`)}
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
export const StyledVenueText = styled(Text)`
|
|
71
|
+
margin: unset;
|
|
72
|
+
margin-top: 0.25rem;
|
|
73
|
+
font-size: 14px;
|
|
74
|
+
color: ${semantics.color.foreground[3]};
|
|
75
|
+
|
|
76
|
+
${media.medium(css`
|
|
77
|
+
font-size: 12px;
|
|
78
|
+
`)}
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
export const StyledFixedSubscribeEventButtonLayoutContainer = styled(motion.div)`
|
|
82
|
+
position: absolute;
|
|
83
|
+
background: transparent;
|
|
84
|
+
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
background: ${semantics.color.background[4]};
|
|
89
|
+
border-radius: 50%;
|
|
90
|
+
|
|
91
|
+
box-shadow: 0 1px 3px ${semantics.color.border[1]}, 0 1px 2px ${semantics.color.border[2]};
|
|
92
|
+
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
|
93
|
+
`;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { withStopPropagation } from '@/utils/with-stop-propagation';
|
|
2
|
+
import { type PropsWithChildren, memo } from 'react';
|
|
3
|
+
import { StyledFixedSubscribeEventButtonLayoutContainer } from './grid-card-item.styled';
|
|
4
|
+
|
|
5
|
+
export const FixedSubscribeEventButtonLayout = memo(
|
|
6
|
+
({
|
|
7
|
+
children,
|
|
8
|
+
customRight = 12,
|
|
9
|
+
customBottom = 12,
|
|
10
|
+
}: PropsWithChildren<{
|
|
11
|
+
customRight?: number;
|
|
12
|
+
customBottom?: number;
|
|
13
|
+
}>) => {
|
|
14
|
+
return (
|
|
15
|
+
<StyledFixedSubscribeEventButtonLayoutContainer
|
|
16
|
+
onClick={withStopPropagation()}
|
|
17
|
+
whileHover={{
|
|
18
|
+
scale: 1.1,
|
|
19
|
+
}}
|
|
20
|
+
transition={{ type: 'spring', stiffness: 300 }}
|
|
21
|
+
style={{
|
|
22
|
+
bottom: customBottom,
|
|
23
|
+
right: customRight,
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</StyledFixedSubscribeEventButtonLayoutContainer>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { WithId } from '@/utils/with-id';
|
|
2
|
+
import { type MouseEventHandler, type ReactNode, memo } from 'react';
|
|
3
|
+
import { match } from 'ts-pattern';
|
|
4
|
+
import { GridCardImage } from '../grid-card-image';
|
|
5
|
+
import {
|
|
6
|
+
StyledGridDate,
|
|
7
|
+
StyledGridImageEmptyContainer,
|
|
8
|
+
StyledGridImageEmptyText,
|
|
9
|
+
StyledGridItem,
|
|
10
|
+
StyledGridTextContainer,
|
|
11
|
+
StyledGridTitle,
|
|
12
|
+
StyledGridTop,
|
|
13
|
+
StyledVenueText,
|
|
14
|
+
} from './grid-card-item.styled';
|
|
15
|
+
import { FixedSubscribeEventButtonLayout } from './grid-card-item.subscribe-btn-layout';
|
|
16
|
+
|
|
17
|
+
export type GridCardListItemProps = WithId<{
|
|
18
|
+
thumbnailUrl: string;
|
|
19
|
+
titleText: string;
|
|
20
|
+
subText: string;
|
|
21
|
+
bottomText?: string;
|
|
22
|
+
isSubscribed?: boolean;
|
|
23
|
+
rightBottomSlot?: {
|
|
24
|
+
type: 'subscribe';
|
|
25
|
+
subscribeEventBtn: ReactNode;
|
|
26
|
+
};
|
|
27
|
+
renderThumbnail?: (url: string) => ReactNode;
|
|
28
|
+
href?: string;
|
|
29
|
+
onClick?: MouseEventHandler<HTMLDivElement | HTMLAnchorElement>;
|
|
30
|
+
}>;
|
|
31
|
+
|
|
32
|
+
export const GridCardItem = memo(
|
|
33
|
+
({
|
|
34
|
+
thumbnailUrl,
|
|
35
|
+
titleText,
|
|
36
|
+
subText,
|
|
37
|
+
bottomText,
|
|
38
|
+
rightBottomSlot,
|
|
39
|
+
renderThumbnail,
|
|
40
|
+
isSubscribed,
|
|
41
|
+
onClick,
|
|
42
|
+
}: GridCardListItemProps) => {
|
|
43
|
+
return (
|
|
44
|
+
<StyledGridItem onClick={onClick}>
|
|
45
|
+
<StyledGridTop>
|
|
46
|
+
{thumbnailUrl ? (
|
|
47
|
+
renderThumbnail ? (
|
|
48
|
+
renderThumbnail(thumbnailUrl)
|
|
49
|
+
) : (
|
|
50
|
+
<GridCardImage src={thumbnailUrl} alt={titleText} />
|
|
51
|
+
)
|
|
52
|
+
) : (
|
|
53
|
+
<StyledGridImageEmptyContainer>
|
|
54
|
+
<StyledGridImageEmptyText>{titleText}</StyledGridImageEmptyText>
|
|
55
|
+
</StyledGridImageEmptyContainer>
|
|
56
|
+
)}
|
|
57
|
+
{match(rightBottomSlot)
|
|
58
|
+
.with(
|
|
59
|
+
{ type: 'subscribe' },
|
|
60
|
+
(value) =>
|
|
61
|
+
typeof isSubscribed === 'boolean' && (
|
|
62
|
+
<FixedSubscribeEventButtonLayout>
|
|
63
|
+
{value.subscribeEventBtn}
|
|
64
|
+
</FixedSubscribeEventButtonLayout>
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
.otherwise(() => null)}
|
|
68
|
+
</StyledGridTop>
|
|
69
|
+
<StyledGridTextContainer>
|
|
70
|
+
<StyledGridTitle as="p" numberOfLines={2}>
|
|
71
|
+
{titleText}
|
|
72
|
+
</StyledGridTitle>
|
|
73
|
+
<StyledGridDate as="p">{subText}</StyledGridDate>
|
|
74
|
+
{bottomText && <StyledVenueText as="p">{bottomText}</StyledVenueText>}
|
|
75
|
+
</StyledGridTextContainer>
|
|
76
|
+
</StyledGridItem>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
GridCardItem.displayName = 'GridCardList.Item';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Text } from '@/base';
|
|
2
|
+
import { semantics } from '@/tokens';
|
|
3
|
+
import { media } from '@/utils';
|
|
4
|
+
import { css } from '@emotion/react';
|
|
5
|
+
import styled from '@emotion/styled';
|
|
6
|
+
|
|
7
|
+
export const StyledListContainer = styled.div`
|
|
8
|
+
margin-top: 1.5rem;
|
|
9
|
+
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export const StyledListHeader = styled.div`
|
|
15
|
+
width: 100%;
|
|
16
|
+
margin-top: 3.5rem;
|
|
17
|
+
|
|
18
|
+
${media.medium(css`
|
|
19
|
+
margin-top: 1.5rem;
|
|
20
|
+
margin-bottom: 2.25rem;
|
|
21
|
+
`)}
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
export const StyledListHeaderText = styled(Text)`
|
|
25
|
+
text-align: center;
|
|
26
|
+
color: ${semantics.color.foreground[2]};
|
|
27
|
+
|
|
28
|
+
font-size: 2rem;
|
|
29
|
+
|
|
30
|
+
${media.medium(css`
|
|
31
|
+
font-size: 1.875rem;
|
|
32
|
+
`)}
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
export const StyledLoadMoreContainer = styled.div`
|
|
36
|
+
display: flex;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
margin-top: 4rem;
|
|
39
|
+
margin-bottom: 4rem;
|
|
40
|
+
|
|
41
|
+
${media.medium(css`
|
|
42
|
+
margin-top: 2rem;
|
|
43
|
+
margin-bottom: 2rem;
|
|
44
|
+
`)}
|
|
45
|
+
`;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Fragment, type ReactNode, memo } from 'react';
|
|
2
|
+
import type { GridCardListItemProps } from '../grid-card-item';
|
|
3
|
+
import { GridCardListLoadMore } from '../grid-card-list-load-more';
|
|
4
|
+
import {
|
|
5
|
+
StyledListContainer,
|
|
6
|
+
StyledListHeader,
|
|
7
|
+
StyledListHeaderText,
|
|
8
|
+
} from './grid-card-list.masonry.styled';
|
|
9
|
+
import { StyledGridContainer, StyledNavigationContainer } from './grid-card-list.styled';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
items: GridCardListItemProps[];
|
|
13
|
+
renderItem: (item: GridCardListItemProps) => ReactNode;
|
|
14
|
+
onLoadMore: () => void;
|
|
15
|
+
headerText?: string;
|
|
16
|
+
hasNextPage?: boolean;
|
|
17
|
+
isEmpty?: boolean;
|
|
18
|
+
emptyComponent?: ReactNode;
|
|
19
|
+
navigationComponent?: ReactNode;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const MasonryGridCardList = memo(
|
|
23
|
+
({
|
|
24
|
+
items,
|
|
25
|
+
renderItem,
|
|
26
|
+
onLoadMore,
|
|
27
|
+
headerText,
|
|
28
|
+
hasNextPage,
|
|
29
|
+
isEmpty,
|
|
30
|
+
emptyComponent,
|
|
31
|
+
navigationComponent,
|
|
32
|
+
}: Props) => {
|
|
33
|
+
return (
|
|
34
|
+
<StyledListContainer>
|
|
35
|
+
{headerText && (
|
|
36
|
+
<StyledListHeader>
|
|
37
|
+
<StyledListHeaderText as="h1">{headerText}</StyledListHeaderText>
|
|
38
|
+
</StyledListHeader>
|
|
39
|
+
)}
|
|
40
|
+
<StyledNavigationContainer>
|
|
41
|
+
{navigationComponent && navigationComponent}
|
|
42
|
+
</StyledNavigationContainer>
|
|
43
|
+
{isEmpty ? (
|
|
44
|
+
emptyComponent
|
|
45
|
+
) : (
|
|
46
|
+
<StyledGridContainer>
|
|
47
|
+
{items.map((item) => (
|
|
48
|
+
<Fragment key={item.id}>{renderItem(item)}</Fragment>
|
|
49
|
+
))}
|
|
50
|
+
</StyledGridContainer>
|
|
51
|
+
)}
|
|
52
|
+
{hasNextPage && <GridCardListLoadMore onLoadMore={onLoadMore} />}
|
|
53
|
+
</StyledListContainer>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
MasonryGridCardList.displayName = 'GridCardList.MasonryList';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Text } from '@/base';
|
|
2
|
+
import { media } from '@/utils';
|
|
3
|
+
import { commonHorizontalLayoutCss } from '@/utils/common-styles';
|
|
4
|
+
import { css } from '@emotion/react';
|
|
5
|
+
import styled from '@emotion/styled';
|
|
6
|
+
|
|
7
|
+
export const StyledGridContainer = styled.div`
|
|
8
|
+
display: grid;
|
|
9
|
+
grid-template-columns: repeat(4, minmax(0px, 1fr));
|
|
10
|
+
gap: 1.25rem;
|
|
11
|
+
|
|
12
|
+
${commonHorizontalLayoutCss(['left', 'right'])}
|
|
13
|
+
|
|
14
|
+
${media.large(css`
|
|
15
|
+
grid-template-columns: repeat(3, minmax(0px, 1fr));
|
|
16
|
+
gap: 1rem;
|
|
17
|
+
`)}
|
|
18
|
+
${media.medium(css`
|
|
19
|
+
grid-template-columns: repeat(2, minmax(0px, 1fr));
|
|
20
|
+
gap: 0.85rem;
|
|
21
|
+
`)}
|
|
22
|
+
${media.small(css`
|
|
23
|
+
grid-template-columns: repeat(2, minmax(0px, 1fr));
|
|
24
|
+
`)}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
export const StyledListContainer = styled.div``;
|
|
28
|
+
|
|
29
|
+
export const StyledListHeader = styled.div`
|
|
30
|
+
width: 100%;
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
export const StyledListHeaderText = styled(Text)``;
|
|
34
|
+
|
|
35
|
+
export const StyledNavigationContainer = styled.div`
|
|
36
|
+
margin-bottom: 3rem;
|
|
37
|
+
${media.small(css`
|
|
38
|
+
margin-bottom: 1.875rem;
|
|
39
|
+
`)}
|
|
40
|
+
`;
|