[web] center standalone homepage content #196
No files matched your search
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@luzzle/web": patch
|
||||
---
|
||||
|
||||
Center custom homepage Markdown below the navigation when both latest and random sections are disabled, while preserving normal layouts when either section is enabled.
|
||||
@@ -27,5 +27,6 @@ export const load: PageServerLoad = async () => {
|
||||
hydrateWithAssets(latestRows),
|
||||
hydrateWithAssets(randomRows)
|
||||
])
|
||||
return { types, body, latest, random }
|
||||
const centerContent = Boolean(body) && !settings.latest && !settings.random
|
||||
return { types, body, latest, random, centerContent }
|
||||
}
|
||||
@@ -22,46 +22,65 @@
|
||||
/>
|
||||
</svelte:head>
|
||||
|
||||
<ContentBanner showRandom showHome={false} />
|
||||
<div class:centered-content={data.centerContent}>
|
||||
<ContentBanner showRandom showHome={false} />
|
||||
|
||||
<main id="main-content">
|
||||
{#if data.body === undefined}
|
||||
<section class="section">
|
||||
<h1>luzzle pieces</h1>
|
||||
<p>export all the <a href={resolve('pieces')}>pieces</a></p>
|
||||
{#if data.types.length}
|
||||
<h2>types</h2>
|
||||
<div class="types-list">
|
||||
{#each data.types as type (type)}
|
||||
<a href={resolve(`pieces/${type}`)} class="type-link">{type}</a>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
{:else if data.body}
|
||||
<section class="section"><Markdown html={data.body} /></section>
|
||||
{/if}
|
||||
|
||||
{#each collections as collection (collection.title)}
|
||||
{#if collection.pieces.length}
|
||||
<main id="main-content">
|
||||
{#if data.body === undefined}
|
||||
<section class="section">
|
||||
<h2>{collection.title}</h2>
|
||||
<div class="pieces-grid">
|
||||
{#each collection.pieces as piece (piece.id)}
|
||||
<a href={resolve(`pieces/${piece.type}/${piece.slug}`)} class="piece">
|
||||
<div class="piece-card">
|
||||
<PieceIcon {piece} size={{ width: 80 }} />
|
||||
<span>{piece.title}</span>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<h1>luzzle pieces</h1>
|
||||
<p>export all the <a href={resolve('pieces')}>pieces</a></p>
|
||||
{#if data.types.length}
|
||||
<h2>types</h2>
|
||||
<div class="types-list">
|
||||
{#each data.types as type (type)}
|
||||
<a href={resolve(`pieces/${type}`)} class="type-link">{type}</a>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
{:else if data.body}
|
||||
<section class="section"><Markdown html={data.body} /></section>
|
||||
{/if}
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
{#each collections as collection (collection.title)}
|
||||
{#if collection.pieces.length}
|
||||
<section class="section">
|
||||
<h2>{collection.title}</h2>
|
||||
<div class="pieces-grid">
|
||||
{#each collection.pieces as piece (piece.id)}
|
||||
<a href={resolve(`pieces/${piece.type}/${piece.slug}`)} class="piece">
|
||||
<div class="piece-card">
|
||||
<PieceIcon {piece} size={{ width: 80 }} />
|
||||
<span>{piece.title}</span>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
{/each}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.centered-content {
|
||||
min-height: 100svh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.centered-content main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.centered-content .section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section {
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
|
||||
@@ -36,7 +36,8 @@ test('stock home uses published latest pieces and does not request random data',
|
||||
types: ['inventory'],
|
||||
body: undefined,
|
||||
latest: recent,
|
||||
random: []
|
||||
random: [],
|
||||
centerContent: false
|
||||
})
|
||||
expect(getRecentPieces).toHaveBeenCalledExactlyOnceWith(db, 5, ['inventory'])
|
||||
expect(getRandomPieces).not.toHaveBeenCalled()
|
||||
@@ -46,24 +47,46 @@ test('Markdown body does not replace dynamic lists and random excludes latest ID
|
||||
config.pages.home.body = 'home.md'
|
||||
config.pages.home.random = true
|
||||
loadPageMarkdown.mockResolvedValue('<h1>Welcome</h1>')
|
||||
expect(await load(event)).toMatchObject({ body: '<h1>Welcome</h1>', latest: recent, random })
|
||||
expect(await load(event)).toMatchObject({
|
||||
body: '<h1>Welcome</h1>',
|
||||
latest: recent,
|
||||
random,
|
||||
centerContent: false
|
||||
})
|
||||
expect(loadPageMarkdown).toHaveBeenCalledExactlyOnceWith('home.md')
|
||||
expect(getRandomPieces).toHaveBeenCalledExactlyOnceWith(db, 5, ['inventory'], ['one'])
|
||||
})
|
||||
|
||||
test('disabled lists skip piece queries and delegate empty collections to hydration', async () => {
|
||||
test('Markdown alone selects the centered layout when both lists are disabled', async () => {
|
||||
config.pages.home.body = 'home.md'
|
||||
config.pages.home.latest = false
|
||||
expect(await load(event)).toMatchObject({ latest: [], random: [] })
|
||||
loadPageMarkdown.mockResolvedValue('<h1>Welcome</h1>')
|
||||
expect(await load(event)).toMatchObject({
|
||||
body: '<h1>Welcome</h1>',
|
||||
latest: [],
|
||||
random: [],
|
||||
centerContent: true
|
||||
})
|
||||
expect(getRecentPieces).not.toHaveBeenCalled()
|
||||
expect(getRandomPieces).not.toHaveBeenCalled()
|
||||
expect(hydrateWithAssets.mock.calls).toEqual([[[]], [[]]])
|
||||
})
|
||||
|
||||
test('random works independently of latest and delegates empty collections to hydration', async () => {
|
||||
test.each([
|
||||
{ label: 'no custom Markdown', file: undefined, body: undefined },
|
||||
{ label: 'empty custom Markdown', file: 'home.md', body: '' }
|
||||
])('$label keeps the normal layout with both lists disabled', async ({ file, body }) => {
|
||||
config.pages.home = { body: file, latest: false, random: false }
|
||||
loadPageMarkdown.mockResolvedValue(body)
|
||||
|
||||
expect(await load(event)).toMatchObject({ body, latest: [], random: [], centerContent: false })
|
||||
})
|
||||
|
||||
test('enabled random keeps the normal layout even when its collection is empty', async () => {
|
||||
config.pages.home.body = 'home.md'
|
||||
config.pages.home.latest = false
|
||||
config.pages.home.random = true
|
||||
loadPageMarkdown.mockResolvedValue('<h1>Welcome</h1>')
|
||||
getRandomPieces.mockResolvedValue([])
|
||||
expect(await load(event)).toMatchObject({ latest: [], random: [] })
|
||||
expect(await load(event)).toMatchObject({ latest: [], random: [], centerContent: false })
|
||||
expect(getRandomPieces).toHaveBeenCalledExactlyOnceWith(db, 5, ['inventory'], [])
|
||||
expect(hydrateWithAssets.mock.calls).toEqual([[[]], [[]]])
|
||||
})
|
||||
Reference in new issue
Block a user