Skip to content

Commit 5747e14

Browse files
authored
Merge pull request #264 from codex-team/home-reload
fix(home): reloading after auth, skeleton
2 parents 176d5f3 + e961579 commit 5747e14

File tree

6 files changed

+280
-71
lines changed

6 files changed

+280
-71
lines changed

codex-ui/dev/pages/components/Card.vue

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
</PageHeader>
88

99
<Heading :level="2">
10-
Horizontal card
10+
Orientation
11+
</Heading>
12+
13+
<Heading :level="3">
14+
Horizontal
1115
</Heading>
1216

1317
<Card
@@ -19,8 +23,8 @@
1923
<Button icon="Plus" />
2024
</Card>
2125

22-
<Heading :level="2">
23-
Vertical card
26+
<Heading :level="3">
27+
Vertical
2428
</Heading>
2529

2630
<Card
@@ -31,11 +35,25 @@
3135
>
3236
<Button icon="Plus" />
3337
</Card>
38+
39+
<br>
40+
<br>
41+
<Heading :level="1">
42+
Card Skeleton
43+
</Heading>
44+
<br>
45+
<br>
46+
47+
<CardSkeleton orientation="horizontal" />
48+
49+
<br>
50+
<br>
51+
<CardSkeleton orientation="vertical" />
3452
</template>
3553

3654
<script setup lang="ts">
3755
import PageHeader from '../../components/PageHeader.vue';
38-
import { Card, Heading, Button } from '../../../src/vue';
56+
import { Card, CardSkeleton, Heading, Button } from '../../../src/vue';
3957
4058
</script>
4159

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<template>
2+
<div
3+
:class="[
4+
$style['card-skeleton'],
5+
$style['card-skeleton--' + orientation]
6+
]"
7+
>
8+
<div
9+
:class="$style['card-skeleton__cover']"
10+
/>
11+
<div :class="$style['card-skeleton__body']">
12+
<div
13+
v-if="titleWidth"
14+
:class="$style['card-skeleton__title']"
15+
/>
16+
<div
17+
v-if="subtitleWidth"
18+
:class="$style['card-skeleton__subtitle']"
19+
/>
20+
</div>
21+
</div>
22+
</template>
23+
24+
<script setup lang="ts">
25+
import { defineProps } from 'vue';
26+
import type { CardOrientation } from './Card.types';
27+
28+
withDefaults(
29+
defineProps<{
30+
/**
31+
* Size of the title skeleton line
32+
* Pass 0 to hide the line
33+
*/
34+
titleWidth?: number;
35+
36+
/**
37+
* Size of the subtitle skeleton line
38+
* Pass 0 to hide the line
39+
*/
40+
subtitleWidth?: number;
41+
42+
/**
43+
* Card variety.
44+
* Card can be vertically oriented (image, body and footer are positioned in vertical direction)
45+
* and horizontally oriented (elements are positioned in horizontal direction)
46+
*/
47+
orientation: CardOrientation;
48+
}>(),
49+
{
50+
titleWidth: 50,
51+
subtitleWidth: 100,
52+
orientation: 'vertical',
53+
}
54+
);
55+
</script>
56+
57+
<style module lang="postcss">
58+
.card-skeleton {
59+
--card-width: 222px;
60+
61+
--skeleton-line-bg: var(--base--text-secondary);
62+
63+
display: flex;
64+
flex-direction: column;
65+
align-items: flex-start;
66+
gap: var(--spacing-ml);
67+
border-radius: var(--radius-m);
68+
padding: var(--v-padding) var(--h-padding);
69+
background-color: var(--base--bg-secondary);
70+
71+
&--horizontal {
72+
width: 100%;
73+
flex-direction: row;
74+
gap: var(--spacing-l);
75+
align-items: center;
76+
box-sizing: border-box;
77+
78+
.card-skeleton__cover {
79+
width: 150px;
80+
height: 100px;
81+
}
82+
}
83+
84+
&__body {
85+
display: flex;
86+
flex-direction: column;
87+
flex: 1;
88+
gap: var(--spacing-m);
89+
}
90+
91+
&__title,
92+
&__subtitle {
93+
height: 9px;
94+
border-radius: var(--radius-m);
95+
}
96+
97+
&__title {
98+
width: v-bind(`${titleWidth}px`);
99+
margin-top: var(--spacing-s);
100+
}
101+
102+
&__subtitle {
103+
width: v-bind(`${subtitleWidth}px`);
104+
}
105+
106+
&--vertical {
107+
width: var(--card-width);
108+
}
109+
110+
&__cover {
111+
flex-shrink: 0;
112+
width: 100%;
113+
aspect-ratio: 222/140;
114+
border-radius: var(--radius-m);
115+
}
116+
117+
&__title,
118+
&__subtitle,
119+
&__cover {
120+
background-color: color-mix(in srgb, var(--skeleton-line-bg) 10%, transparent);
121+
background-image: linear-gradient(
122+
to left,
123+
color-mix(in srgb, var(--skeleton-line-bg) 30%, transparent) 0%,
124+
color-mix(in srgb, var(--skeleton-line-bg) 10%, transparent) 50%,
125+
color-mix(in srgb, var(--skeleton-line-bg) 30%, transparent) 100%
126+
);
127+
background-size: 200% 100%;
128+
animation: skeleton-animation 3s infinite linear;
129+
}
130+
}
131+
132+
@keyframes skeleton-animation {
133+
0% {
134+
background-position: 200% 0;
135+
}
136+
100% {
137+
background-position: -200% 0
138+
}
139+
}
140+
141+
</style>
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
import Card from './Card.vue';
2+
import CardSkeleton from './CardSkeleton.vue';
23

3-
export { Card };
4+
export {
5+
Card,
6+
CardSkeleton
7+
};

src/application/services/useNoteList.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ interface UseNoteListComposableState {
2929
* Load next page of the notes
3030
*/
3131
loadMoreNotes: () => Promise<void>;
32+
33+
/**
34+
* Loading state
35+
*/
36+
isLoading: Ref<boolean>;
3237
}
3338

3439
/**
@@ -57,12 +62,23 @@ export default function (): UseNoteListComposableState {
5762
*/
5863
let currentPage = 0;
5964

65+
/**
66+
* Loading state
67+
*/
68+
const isLoading = ref(false);
69+
6070
/**
6171
* Get note list
6272
* @param page - number of pages
6373
*/
6474
const load = async (page: number): Promise<NoteList> => {
65-
return await noteListService.getNoteList(page);
75+
isLoading.value = true;
76+
77+
const list = await noteListService.getNoteList(page);
78+
79+
isLoading.value = false;
80+
81+
return list;
6682
};
6783

6884
/**
@@ -116,5 +132,6 @@ export default function (): UseNoteListComposableState {
116132
hasMoreNotes,
117133
load,
118134
loadMoreNotes,
135+
isLoading,
119136
};
120137
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<template>
2+
<div v-if="noteList?.items.length === 0">
3+
<p>{{ t('noteList.emptyNoteList') }}</p>
4+
</div>
5+
6+
<div
7+
:class="$style['notes-container']"
8+
>
9+
<template v-if="noteList">
10+
<RouterLink
11+
v-for="note in noteList.items"
12+
:key="note.id"
13+
:to="`/note/${note.id}`"
14+
>
15+
<Card
16+
:title="getTitle(note.content)"
17+
:subtitle="getSubtitle(note)"
18+
:src="note.cover || undefined"
19+
orientation="vertical"
20+
/>
21+
</RouterLink>
22+
</template>
23+
<template v-if="isLoading">
24+
<CardSkeleton
25+
v-for="index in 6"
26+
:key="index"
27+
orientation="vertical"
28+
/>
29+
</template>
30+
</div>
31+
<Button
32+
v-if="hasMoreNotes"
33+
:class="$style.button"
34+
secondary
35+
@click="loadMoreNotes"
36+
>
37+
{{ $t('loadMore') }}
38+
</Button>
39+
</template>
40+
41+
<script setup lang="ts">
42+
import useNoteList from '@/application/services/useNoteList';
43+
import type { Note } from '@/domain/entities/Note';
44+
import { formatShortDate } from '@/infrastructure/utils/date';
45+
import { getTitle } from '@/infrastructure/utils/note';
46+
import { useI18n } from 'vue-i18n';
47+
import { Card, CardSkeleton, Button } from 'codex-ui/vue';
48+
49+
const {
50+
noteList,
51+
loadMoreNotes,
52+
hasMoreNotes,
53+
isLoading,
54+
} = useNoteList();
55+
const { t } = useI18n();
56+
57+
/**
58+
* Returns card subtitle text
59+
*
60+
* @param note - Note entity
61+
*
62+
* @returns {string | undefined}
63+
*/
64+
function getSubtitle(note: Note): string | undefined {
65+
if (note.updatedAt === undefined) {
66+
return;
67+
}
68+
69+
return `${t('home.updated')} ${formatShortDate(note.updatedAt)}`;
70+
}
71+
72+
</script>
73+
74+
<style lang="postcss" module>
75+
.notes-container {
76+
padding: var(--spacing-xxl) 0;
77+
gap: var(--spacing-ml);
78+
display: grid;
79+
width: 100%;
80+
box-sizing: border-box;
81+
grid-template-columns: repeat(3, 1fr);
82+
}
83+
84+
.button {
85+
margin-top: var(--spacing-l);
86+
}
87+
</style>

0 commit comments

Comments
 (0)