mirror of
https://github.com/BradNut/personal-website-sveltekit
synced 2025-09-08 23:20:18 +00:00
Updating loading of articles to use a skeleton article while loading.
This commit is contained in:
parent
5752c125ee
commit
bc367cf7d2
7 changed files with 220 additions and 145 deletions
|
|
@ -21,7 +21,7 @@
|
||||||
"@internationalized/date": "^3.8.2",
|
"@internationalized/date": "^3.8.2",
|
||||||
"@playwright/test": "^1.54.2",
|
"@playwright/test": "^1.54.2",
|
||||||
"@sveltejs/enhanced-img": "^0.5.1",
|
"@sveltejs/enhanced-img": "^0.5.1",
|
||||||
"@sveltejs/kit": "^2.28.0",
|
"@sveltejs/kit": "^2.29.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.1.1",
|
"@sveltejs/vite-plugin-svelte": "^5.1.1",
|
||||||
"@unpic/svelte": "^1.0.0",
|
"@unpic/svelte": "^1.0.0",
|
||||||
"@zerodevx/svelte-img": "^2.1.2",
|
"@zerodevx/svelte-img": "^2.1.2",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ importers:
|
||||||
version: 2.6.2
|
version: 2.6.2
|
||||||
'@sveltejs/adapter-node':
|
'@sveltejs/adapter-node':
|
||||||
specifier: ^5.2.14
|
specifier: ^5.2.14
|
||||||
version: 5.2.14(@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))
|
version: 5.2.14(@sveltejs/kit@2.29.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))
|
||||||
'@vercel/og':
|
'@vercel/og':
|
||||||
specifier: ^0.6.8
|
specifier: ^0.6.8
|
||||||
version: 0.6.8
|
version: 0.6.8
|
||||||
|
|
@ -52,8 +52,8 @@ importers:
|
||||||
specifier: ^0.5.1
|
specifier: ^0.5.1
|
||||||
version: 0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
version: 0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
||||||
'@sveltejs/kit':
|
'@sveltejs/kit':
|
||||||
specifier: ^2.28.0
|
specifier: ^2.29.0
|
||||||
version: 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
version: 2.29.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^5.1.1
|
specifier: ^5.1.1
|
||||||
version: 5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
version: 5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
||||||
|
|
@ -1210,8 +1210,8 @@ packages:
|
||||||
svelte: ^5.0.0
|
svelte: ^5.0.0
|
||||||
vite: '>= 5.0.0'
|
vite: '>= 5.0.0'
|
||||||
|
|
||||||
'@sveltejs/kit@2.28.0':
|
'@sveltejs/kit@2.29.0':
|
||||||
resolution: {integrity: sha512-qrhygwHV5r6JrvCw4gwNqqxYGDi5YbajocxfKgFXmSFpFo8wQobUvsM0OfakN4h+0LEmXtqHRrC6BcyAkOwyoQ==}
|
resolution: {integrity: sha512-gOynQRBThrtF/RjljB8Oybs9VHVmLbk9q7E7ALJT6ImppJtc/yx3sTGiBV64y+lwmagnBCmEMmJ40CVChGy8lA==}
|
||||||
engines: {node: '>=18.13'}
|
engines: {node: '>=18.13'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -3303,12 +3303,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
|
|
||||||
'@sveltejs/adapter-node@5.2.14(@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))':
|
'@sveltejs/adapter-node@5.2.14(@sveltejs/kit@2.29.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.8)
|
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.8)
|
||||||
'@rollup/plugin-json': 6.1.0(rollup@4.34.8)
|
'@rollup/plugin-json': 6.1.0(rollup@4.34.8)
|
||||||
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.34.8)
|
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.34.8)
|
||||||
'@sveltejs/kit': 2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
'@sveltejs/kit': 2.29.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))
|
||||||
rollup: 4.34.8
|
rollup: 4.34.8
|
||||||
|
|
||||||
'@sveltejs/enhanced-img@0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
|
'@sveltejs/enhanced-img@0.5.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(rollup@4.34.8)(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
|
||||||
|
|
@ -3324,7 +3324,7 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
|
|
||||||
'@sveltejs/kit@2.28.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
|
'@sveltejs/kit@2.29.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0)))(svelte@5.38.1)(vite@6.3.5(yaml@2.7.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.0.0
|
'@standard-schema/spec': 1.0.0
|
||||||
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
|
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Article } from '$lib/types/article';
|
import { ArrowRight } from "lucide-svelte";
|
||||||
import { ArrowRight } from 'lucide-svelte';
|
import { beforeNavigate, onNavigate } from "$app/navigation";
|
||||||
import ExternalLink from './ExternalLink.svelte';
|
import { page } from "$app/state";
|
||||||
|
import ArticlesSkeleton from "$lib/components/ArticlesSkeleton.svelte";
|
||||||
|
import type { Article } from "$lib/types/article";
|
||||||
|
import ExternalLink from "./ExternalLink.svelte";
|
||||||
|
|
||||||
type LoadData = {
|
type LoadData = {
|
||||||
articles: Article[];
|
articles: Article[];
|
||||||
|
|
@ -19,42 +22,47 @@
|
||||||
const classes = $derived(data.classes || []);
|
const classes = $derived(data.classes || []);
|
||||||
|
|
||||||
const articlesData = $derived(articles);
|
const articlesData = $derived(articles);
|
||||||
|
let loadingArticles = $state(false);
|
||||||
|
|
||||||
|
beforeNavigate(() => {
|
||||||
|
loadingArticles = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
onNavigate((navigation) => {
|
||||||
|
loadingArticles = true;
|
||||||
|
|
||||||
|
// Resolve the promise when the page is done loading
|
||||||
|
navigation?.complete.then(() => {
|
||||||
|
loadingArticles = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="articles">
|
<section class="articles">
|
||||||
<h2>Favorite Articles</h2>
|
<h2>Favorite Articles</h2>
|
||||||
<div class={classes.join(' ')}>
|
<div class={classes.join(" ")}>
|
||||||
<!-- {#await data.articles}
|
{#if loadingArticles}
|
||||||
{#each Array(6) as _, i (i)}
|
<ArticlesSkeleton count={6} />
|
||||||
<article class="card skeleton">
|
{:else}
|
||||||
<section>
|
|
||||||
<h3><span class="skeleton-text skeleton-title" aria-hidden="true">Loading article title...</span></h3>
|
|
||||||
<span class="skeleton-text skeleton-domain" aria-hidden="true">Loading domain...</span>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<span class="skeleton-text skeleton-reading" aria-hidden="true">Loading reading time...</span>
|
|
||||||
<span class="skeleton-text skeleton-tags" aria-hidden="true">Loading tags...</span>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
{/each}
|
|
||||||
{:then articles} -->
|
|
||||||
{#each articlesData as article (article.hashed_url)}
|
{#each articlesData as article (article.hashed_url)}
|
||||||
<article class="card">
|
<article class="card">
|
||||||
<section>
|
<section>
|
||||||
<h3>
|
<h3>
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
textData={{
|
textData={{
|
||||||
text: compact ? article.title.substring(0, 50).trim() : article.title,
|
text: compact
|
||||||
location: 'left',
|
? article.title.substring(0, 50).trim()
|
||||||
|
: article.title,
|
||||||
|
location: "left",
|
||||||
showIcon: true,
|
showIcon: true,
|
||||||
}}
|
}}
|
||||||
linkData={{
|
linkData={{
|
||||||
href: article.url.toString(),
|
href: article.url.toString(),
|
||||||
ariaLabel: `Link to ${article.title}`,
|
ariaLabel: `Link to ${article.title}`,
|
||||||
title: `Link to ${article.title}`,
|
title: `Link to ${article.title}`,
|
||||||
target: '_blank',
|
target: "_blank",
|
||||||
}}
|
}}
|
||||||
iconData={{ iconClass: 'center' }}
|
iconData={{ iconClass: "center" }}
|
||||||
/>
|
/>
|
||||||
</h3>
|
</h3>
|
||||||
<p>{article.domain_name}</p>
|
<p>{article.domain_name}</p>
|
||||||
|
|
@ -70,14 +78,15 @@
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
{/each}
|
{/each}
|
||||||
<!-- {:catch error}
|
{/if}
|
||||||
<p>There was an error loading the articles.</p>
|
|
||||||
{/await} -->
|
|
||||||
</div>
|
</div>
|
||||||
<a class="moreArticles" href="/articles">{`${totalArticles} more articles`} <ArrowRight /></a>
|
{#if page.url.pathname === "/"}
|
||||||
|
<a class="moreArticles" href="/articles"
|
||||||
|
>{`${totalArticles} more articles`} <ArrowRight /></a
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
article {
|
article {
|
||||||
margin: 1.5rem 0;
|
margin: 1.5rem 0;
|
||||||
|
|
|
||||||
|
|
@ -4,42 +4,45 @@
|
||||||
classes?: string[];
|
classes?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let { count = 6, classes = ['columns'] }: Props = $props();
|
let { count = 6, classes = [""] }: Props = $props();
|
||||||
const placeholders = Array.from({ length: count });
|
const placeholders = Array.from({ length: count });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={classes.join(' ')} role="status" aria-live="polite" aria-busy="true">
|
|
||||||
{#each placeholders as _, i (i)}
|
{#each placeholders as _, i (i)}
|
||||||
<article class="card skeleton">
|
<article class={`card skeleton ${classes.join(" ")}`}>
|
||||||
<section>
|
<section>
|
||||||
<h3><span class="skeleton-text skeleton-title" aria-hidden="true">Loading article title...</span></h3>
|
<h3>
|
||||||
<span class="skeleton-text skeleton-domain" aria-hidden="true">Loading domain...</span>
|
<span class="skeleton-text skeleton-title" aria-hidden="true"
|
||||||
|
>Loading article title...</span
|
||||||
|
>
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
<span class="skeleton-text skeleton-domain" aria-hidden="true"
|
||||||
|
>Loading domain...</span
|
||||||
|
>
|
||||||
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<span class="skeleton-text skeleton-reading" aria-hidden="true">Loading reading time...</span>
|
<p>
|
||||||
<span class="skeleton-text skeleton-tags" aria-hidden="true">Loading tags...</span>
|
<span class="skeleton-text skeleton-reading" aria-hidden="true"
|
||||||
|
>Loading reading time...</span
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="skeleton-text skeleton-tags" aria-hidden="true"
|
||||||
|
>Loading tags...</span
|
||||||
|
>
|
||||||
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.columns {
|
p {
|
||||||
display: grid;
|
min-height: 1em;
|
||||||
grid-template-columns: repeat(2, minmax(250px, 1fr));
|
line-height: 1.2;
|
||||||
min-height: 800px;
|
padding: 0.25rem 0.5rem;
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
grid-template-columns: repeat(2, minmax(250px, 1fr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 650px) {
|
|
||||||
grid-template-columns: minmax(250px, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
gap: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeleton {
|
.skeleton {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -51,7 +54,6 @@
|
||||||
|
|
||||||
.skeleton-text {
|
.skeleton-text {
|
||||||
display: block;
|
display: block;
|
||||||
height: 1rem;
|
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
|
|
@ -62,19 +64,52 @@
|
||||||
);
|
);
|
||||||
background-size: 200% 100%;
|
background-size: 200% 100%;
|
||||||
animation: shimmer 1.2s ease-in-out infinite;
|
animation: shimmer 1.2s ease-in-out infinite;
|
||||||
|
min-height: 1.25em;
|
||||||
|
line-height: 1.25em;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
color: transparent; /* hide placeholder text */
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeleton-title {
|
.skeleton-title {
|
||||||
height: 1.25rem;
|
height: 1.6em;
|
||||||
width: 80%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeleton-domain { width: 40%; }
|
.skeleton-domain {
|
||||||
.skeleton-reading { width: 55%; }
|
width: 40%;
|
||||||
.skeleton-tags { width: 65%; }
|
height: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-reading {
|
||||||
|
width: 55%;
|
||||||
|
height: 1.25em;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-tags {
|
||||||
|
width: 65%;
|
||||||
|
height: 1.6em; /* closer to tag chip height */
|
||||||
|
border-radius: 9999px; /* pill-like to match tags */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* layout tweaks to avoid overlap and match spacing */
|
||||||
|
.card.skeleton {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
.skeleton > section {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.skeleton > section + section {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes shimmer {
|
@keyframes shimmer {
|
||||||
0% { background-position: 200% 0; }
|
0% {
|
||||||
100% { background-position: -200% 0; }
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onNavigate, beforeNavigate } from "$app/navigation";
|
import { onNavigate, beforeNavigate } from "$app/navigation";
|
||||||
|
import { LoaderCircle } from "lucide-svelte";
|
||||||
|
|
||||||
let visible = $state(false);
|
let visible = $state(false);
|
||||||
let progress = $state(0);
|
let progress = $state(0);
|
||||||
|
|
@ -57,6 +58,9 @@
|
||||||
|
|
||||||
{#if visible}
|
{#if visible}
|
||||||
<div class="progress" style="width: {progress}%;"></div>
|
<div class="progress" style="width: {progress}%;"></div>
|
||||||
|
<div class="loader-container">
|
||||||
|
<LoaderCircle class="loader-icon" size={20} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
|
@ -70,4 +74,29 @@
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loader-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
z-index: 50;
|
||||||
|
pointer-events: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.loader-icon) {
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
color: var(--lightGrey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
|
||||||
import type { ArticlePageLoad } from '$lib/types/article';
|
|
||||||
import type { MetaTagsProps } from 'svelte-meta-tags';
|
import type { MetaTagsProps } from 'svelte-meta-tags';
|
||||||
|
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ fetch, params, setHeaders, url, parent }) => {
|
export const load: PageServerLoad = async ({ fetch, params, setHeaders, url, parent }) => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Articles from '$lib/components/Articles.svelte';
|
import Articles from "$lib/components/Articles.svelte";
|
||||||
import Pagination from '$lib/components/Pagination.svelte';
|
import Pagination from "$lib/components/Pagination.svelte";
|
||||||
import ArticlesSkeleton from '$lib/components/ArticlesSkeleton.svelte';
|
import type { PageData } from "./$types";
|
||||||
import type { PageData } from './$types';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: PageData;
|
data: PageData;
|
||||||
|
|
@ -16,6 +15,8 @@
|
||||||
let totalArticles: number = $derived(data?.totalArticles || 0);
|
let totalArticles: number = $derived(data?.totalArticles || 0);
|
||||||
let limit: number = $derived(data?.limit || 10);
|
let limit: number = $derived(data?.limit || 10);
|
||||||
let totalPages: number = $derived(data?.totalPages || 1);
|
let totalPages: number = $derived(data?.totalPages || 1);
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="articles-content">
|
<div class="articles-content">
|
||||||
|
|
@ -28,7 +29,9 @@
|
||||||
base="/articles"
|
base="/articles"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Articles data={{ articles, totalArticles, classes: ['columns'], compact: false }} />
|
<Articles
|
||||||
|
data={{ articles, totalArticles, classes: ["columns"], compact: false }}
|
||||||
|
/>
|
||||||
|
|
||||||
<Pagination
|
<Pagination
|
||||||
additionalClasses="bottom-pagination"
|
additionalClasses="bottom-pagination"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue