Skip to content

Commit 3812fa4

Browse files
committed
home page reloading
1 parent 7b00e6b commit 3812fa4

File tree

6 files changed

+274
-71
lines changed

6 files changed

+274
-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: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,23 @@ export default function (): UseNoteListComposableState {
5757
*/
5858
let currentPage = 0;
5959

60+
/**
61+
* Loading state
62+
*/
63+
const isLoading = ref(false);
64+
6065
/**
6166
* Get note list
6267
* @param page - number of pages
6368
*/
6469
const load = async (page: number): Promise<NoteList> => {
65-
return await noteListService.getNoteList(page);
70+
isLoading.value = true;
71+
72+
const list = await noteListService.getNoteList(page);
73+
74+
isLoading.value = false;
75+
76+
return list;
6677
};
6778

6879
/**
@@ -116,5 +127,6 @@ export default function (): UseNoteListComposableState {
116127
hasMoreNotes,
117128
load,
118129
loadMoreNotes,
130+
isLoading,
119131
};
120132
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
@click="loadMoreNotes"
35+
>
36+
{{ $t('loadMore') }}
37+
</Button>
38+
</template>
39+
40+
<script setup lang="ts">
41+
import useNoteList from '@/application/services/useNoteList';
42+
import type { Note } from '@/domain/entities/Note';
43+
import { formatShortDate } from '@/infrastructure/utils/date';
44+
import { getTitle } from '@/infrastructure/utils/note';
45+
import { useI18n } from 'vue-i18n';
46+
import { Card, CardSkeleton, Button } from 'codex-ui/vue';
47+
48+
const {
49+
noteList,
50+
loadMoreNotes,
51+
hasMoreNotes,
52+
isLoading,
53+
} = useNoteList();
54+
const { t } = useI18n();
55+
56+
/**
57+
* Returns card subtitle text
58+
*
59+
* @param note - Note entity
60+
*
61+
* @returns {string | undefined}
62+
*/
63+
function getSubtitle(note: Note): string | undefined {
64+
if (note.updatedAt === undefined) {
65+
return;
66+
}
67+
68+
return t('home.updated') + ' ' + formatShortDate(note.updatedAt);
69+
}
70+
71+
</script>
72+
73+
<style lang="postcss" module>
74+
.notes-container {
75+
padding: var(--spacing-xxl) 0;
76+
gap: var(--spacing-ml);
77+
display: grid;
78+
width: 100%;
79+
box-sizing: border-box;
80+
grid-template-columns: repeat(3, 1fr);
81+
}
82+
83+
.button {
84+
margin-top: var(--spacing-l);
85+
}
86+
</style>

0 commit comments

Comments
 (0)