Improve Item page

Add 500 page and dedicated 404 page
Add fake cache to tester API
Adjust some styles for better readability and usability
This commit is contained in:
Michał 2024-04-28 19:19:05 +01:00
parent 40c19335cf
commit 383f22bdf8
11 changed files with 297 additions and 91 deletions

View file

@ -14,20 +14,19 @@
cart: {path: '/cart', className: 'active'}, cart: {path: '/cart', className: 'active'},
} }
let windowScrollY = 0; let scrollY = 0;
let windowWidth = 0; let width = 0;
let oldLocation = undefined; let oldLocation = undefined;
let fullWidth = false; let fullWidth = false;
let showNavBar = false; let showNavBar = false;
$: scrolled = windowScrollY > 0
$: mobile = windowWidth < 700
function routeLoading(event) { function routeLoading(event) {
if (event.detail.location === oldLocation) { if (event.detail.location === oldLocation) {
console.log("Fake!");
return; // not an actual change return; // not an actual change
} }
showNavBar = event.detail.userData.showNavBar; showNavBar = event.detail.userData.showNavBar;
fullWidth = event.detail.userData.fullWidth; fullWidth = event.detail.userData.fullWidth;
oldLocation = event.detail.location; oldLocation = event.detail.location;
@ -38,15 +37,18 @@
} }
</script> </script>
<svelte:window bind:scrollY={windowScrollY} bind:innerWidth={windowWidth} /> <svelte:window
bind:scrollY={scrollY}
bind:innerWidth={width}
/>
<svelte:head> <svelte:head>
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=erode@300,301,400,401,500,501,600,601,700,701,1,2&display=swap"> <link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=erode@300,301,400,401,500,501,600,601,700,701,1,2&display=swap">
</svelte:head> </svelte:head>
{#if showNavBar } {#if showNavBar }
<nav class:scrolled={scrolled} class:mobile={mobile}> <nav class:scrolled={scrollY > 0} class:mobile={width < 700}>
{#if !mobile} {#if !(width < 700)}
<ul style="justify-content: flex-end"> <ul style="justify-content: flex-end">
<li use:active={links.home}><a href="/" use:link>Home</a></li> <li use:active={links.home}><a href="/" use:link>Home</a></li>
<li use:active={links.menu}><a href="/menu" use:link>Menu</a></li> <li use:active={links.menu}><a href="/menu" use:link>Menu</a></li>

View file

@ -6,9 +6,7 @@
{#await announcement} {#await announcement}
<div class="announcement-banner-loading"> <div class="announcement-banner-loading" />
<div />
</div>
{:then announcement} {:then announcement}
<div class="announcement-banner"> <div class="announcement-banner">
<img src={announcement.image} alt=""> <img src={announcement.image} alt="">
@ -35,12 +33,15 @@
overflow: hidden; overflow: hidden;
> div { &::after {
content: '';
position: absolute; position: absolute;
top: $padding; top: $padding;
right: $padding; right: $padding;
bottom: $padding; bottom: $padding;
left: $padding; left: $padding;
border-radius: calc($border-radius-large - $padding); border-radius: calc($border-radius-large - $padding);
background-color: rgba($color-background, 0.9); background-color: rgba($color-background, 0.9);
} }

View file

@ -36,7 +36,7 @@
align-items: center; align-items: center;
p { p {
font-size: $font-size-h5; font-size: $font-size-h6;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
} }

View file

@ -4,23 +4,19 @@
import LoadingImage from '/MenuItemLoadingAlt.svg'; import LoadingImage from '/MenuItemLoadingAlt.svg';
export let id; export let item = {};
export let name;
export let price;
export let image;
export let labels = []
</script> </script>
<div class="menu-item"> <div class="menu-item">
{#if !image} {#if !item.image}
<img src={LoadingImage} alt="" class="menu-item-image"> <img src={LoadingImage} alt="" class="menu-item-image">
{:else} {:else}
<img src={image} alt="" class="menu-item-image"> <img src={item.image} alt="" class="menu-item-image">
{/if} {/if}
<div class="menu-item-header"> <div class="menu-item-header">
<ul> <ul>
{#each labels as label} {#each item.labels as label}
{#if label === "vegan"} {#if label === "vegan"}
<li class="vegan"><Leaf weight="fill" /></li> <li class="vegan"><Leaf weight="fill" /></li>
{/if} {/if}
@ -38,12 +34,14 @@
{/if} {/if}
{/each} {/each}
</ul> </ul>
<a href="/item/{id}" use:link>View&nbsp;<ArrowUpRight /></a> <a href="/item/{item.uuid}" use:link>
View&nbsp;<ArrowUpRight />
</a>
</div> </div>
<ul class="menu-item-detail"> <ul class="menu-item-detail">
<li>{name}</li> <li>{item.name}</li>
<li>£{price}</li> <li>£{item.price}</li>
</ul> </ul>
</div> </div>

View file

@ -7,13 +7,7 @@
<ul> <ul>
{#each items as item} {#each items as item}
<li> <li>
<MenuItem <MenuItem item={item} />
id={item.name}
name={item.name}
price={item.price}
image={item.image}
labels={item.labels}
/>
</li> </li>
{/each} {/each}
</ul> </ul>
@ -31,4 +25,4 @@
li { li {
margin: 0; margin: 0;
} }
</style> </style>

View file

@ -1,19 +1,32 @@
import Items from '%/lib/test-data.js'; import Items from '%/lib/test-data.js';
let cache = {};
async function fakeDelay(timeout = 1000) { async function fakeDelay(timeout = 1000) {
await new Promise(resolve => setTimeout(resolve, timeout)); await new Promise(resolve => setTimeout(resolve, timeout));
} }
export async function getAnnouncements() { export async function getAnnouncements() {
if (cache.announcement_banner !== undefined) {
return cache.announcement_banner;
}
const data = { const data = {
image: "/BannerExampleImage.jpg", image: "/BannerExampleImage.jpg",
}; };
await fakeDelay(2000) cache.announcement_banner = data;
await fakeDelay(5000)
return data; return data;
} }
export async function getPopularToday() { export async function getPopularToday() {
if (cache.popular_today !== undefined) {
return cache.popular_today;
}
const data = Items; const data = Items;
cache.popular_today = data;
await fakeDelay(2000) await fakeDelay(2000)
return data; return data;
} }
@ -33,6 +46,24 @@ export async function getMenuItems() {
items: Items, items: Items,
}, },
]; ];
await fakeDelay(2000) await fakeDelay(20)
return data; return data;
} }
export async function getItemByUUID(uuid) {
let data;
Items.forEach((item) => {
if (item.uuid === uuid) {
data = item;
}
})
await fakeDelay(1000)
if (!data) {
throw new Error("Resource could not be found");
}
return data;
}

View file

@ -7,6 +7,7 @@ const Items = [
name: "Bar of Soap", name: "Bar of Soap",
price: 69.99, price: 69.99,
labels: ["vegan", "spicy"], labels: ["vegan", "spicy"],
detail: "Example",
}, },
// sock: { // sock: {
{ {
@ -14,6 +15,7 @@ const Items = [
name: "Sock", name: "Sock",
price: 21, price: 21,
labels: ["vegan", "fish", "nut", "spicy"], labels: ["vegan", "fish", "nut", "spicy"],
detail: "Example",
}, },
// brick: { // brick: {
{ {
@ -21,6 +23,7 @@ const Items = [
name: "Brick", name: "Brick",
price: 0, price: 0,
labels: ["spicy"], labels: ["spicy"],
detail: "Example",
}, },
// toast: { // toast: {
{ {
@ -28,6 +31,7 @@ const Items = [
name: "Toast", name: "Toast",
price: 4382749832743, price: 4382749832743,
labels: ["gluten"], labels: ["gluten"],
detail: "Example",
}, },
// water: { // water: {
{ {
@ -35,6 +39,7 @@ const Items = [
name: "water", name: "water",
price: 1, price: 1,
labels: ["fish"], labels: ["fish"],
detail: "Example",
}, },
// mouldy_bread: { // mouldy_bread: {
{ {
@ -42,6 +47,7 @@ const Items = [
name: "half eaten mouldy bread", name: "half eaten mouldy bread",
price: -99, price: -99,
labels: ["nut"], labels: ["nut"],
detail: "Example",
}, },
// gwagwa: { // gwagwa: {
{ {
@ -58,6 +64,7 @@ const Items = [
price: "1111", price: "1111",
labels: ["fish"], labels: ["fish"],
image: "/wathog.jpg", image: "/wathog.jpg",
detail: "Example",
}, },
// bluhog: { // bluhog: {
{ {
@ -66,6 +73,7 @@ const Items = [
price: "ARUGH", price: "ARUGH",
labels: ["nut", "gluten", "spicy"], labels: ["nut", "gluten", "spicy"],
image: "/sonichog.jpg", image: "/sonichog.jpg",
detail: "Example",
}, },
]; ];

View file

@ -0,0 +1,32 @@
<script>
import { SmileySad } from "phosphor-svelte";
</script>
<div>
<h1>Server Fucking Died!&nbsp;<SmileySad weight="fill" /></h1>
<p>Error 500</p>
</div>
<style lang="scss">
@import "%/styles/vars";
div {
padding: $spacing-large;
height: 100%;
display: flex;
flex-direction: column;
}
h1 {
display: flex;
justify-content: center;
align-items: center;
font-size: 50px;
text-align: center;
}
p {
text-align: center;
}
</style>

View file

@ -119,6 +119,7 @@
min-width: 250px; min-width: 250px;
max-width: calc(100vw - calc(2 * $spacing-normal)); max-width: calc(100vw - calc(2 * $spacing-normal));
resize: none; resize: none;
overflow: hidden;
} }
button { button {

View file

@ -1,95 +1,161 @@
<script> <script>
import { replace } from "svelte-spa-router";
import MenuList from "%/components/MenuList.svelte"; import MenuList from "%/components/MenuList.svelte";
import LoadingBar from "%/components/LoadingBar.svelte";
import { getPopularToday, getItemByUUID } from "%/lib/test-api.js";
import LoadingImage from "/MenuItemLoading.svg"; import LoadingImage from "/MenuItemLoading.svg";
import Items from '%/lib/test-data.js';
let items = Items; export let params;
export let params = {}; $: item = getItemByUUID(params.uuid)
// ToDo: Fix this, keeps fucking breaking
// NOT WORKING FUCK
// .catch((error) => {
// console.error(error);
// if (error === "404") {
// replace("/ForOhFor");
// }
// replace("/ServerError");
// });
let popularToday = getPopularToday();
</script> </script>
<div class="main"> <div class="main">
<div class="images"> {#await item}
<div> <div id="images">
<img src={LoadingImage} alt=""> <div>
<img src={LoadingImage} alt="">
</div>
<ul>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
</ul>
</div> </div>
<ul>
<li><img src={LoadingImage} alt=""></li> <div id="info">
<li><img src={LoadingImage} alt=""></li> <div class="loading title" />
<li><img src={LoadingImage} alt=""></li> <div class="loading price" />
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li> <div class="loading description" />
</ul> </div>
</div> {:then item}
<div class="info"> <div id="images">
<h2>{params.name}</h2> <div>
</div> <img src={item.image} alt="">
</div>
<ul>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
<li><img src={LoadingImage} alt=""></li>
</ul>
</div>
<div id="info">
<h2>{item.name}</h2>
<p>£{item.price}</p>
<div class="container">
<p>{item.detail}</p>
</div>
</div>
{:catch error}
<p>Server fucking died...</p>
<p>{error}</p>
{/await}
</div> </div>
<div class="spacer"></div> <div class="spacer"></div>
<div class="other"> <div class="other">
<h2>Popular</h2> <h2>Popular</h2>
<MenuList items={items} /> <div id="popular">
{#await popularToday}
<LoadingBar />
{:then items}
<MenuList {items} />
{:catch error}
<p>{error}</p>
{/await}
</div>
</div> </div>
<style lang="scss"> <style lang="scss">
@import "%/styles/vars"; @import "%/styles/vars";
h2 { $padding: 1px;
margin-bottom: $spacing-small;
}
.spacer {
height: $spacing-large;
}
.main { .main {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
}
#images {
display: flex;
flex-direction: column;
> div {
margin-bottom: $spacing-small;
width: 650px;
height: 500px;
.images {
display: flex; display: flex;
flex-direction: column; justify-content: center;
align-items: center;
> div { overflow: hidden;
margin-bottom: $spacing-small;
width: 650px; > img {
height: 500px; max-width: 650px;
max-height: 500px;
display: flex; border-radius: $border-radius-normal;
justify-content: center; }
align-items: center; }
//border-radius: $border-radius-large; > ul {
//background-color: $color-light; margin: 0;
padding: 0;
overflow: hidden; display: flex;
flex-direction: row;
> li {
list-style: none;
> img { > img {
max-width: 650px; margin-right: $spacing-small;
max-height: 500px; width: 100px;
border-radius: $border-radius-normal; border-radius: $border-radius-normal;
} }
} }
}
}
> ul { #info {
margin: 0; width: 100%;
padding: 0;
display: flex; display: flex;
flex-direction: row; flex-direction: column;
align-items: flex-end;
> li { > h2 {
list-style: none; font-size: $font-size-h1;
padding-bottom: $spacing-small;
> img { }
margin-right: $spacing-small; > p {
width: 100px; font-size: $font-size-h2;
border-radius: $border-radius-normal; padding-bottom: $spacing-normal;
} }
} .container {
} padding: $spacing-normal;
width: 100%;
} }
} }
@ -97,4 +163,65 @@
margin: 0 auto; margin: 0 auto;
max-width: $sizing-default-width; max-width: $sizing-default-width;
} }
#popular {
position: relative;
}
.loading {
position: relative;
border-radius: $border-radius-large;
background: linear-gradient(to right, $color-background 8%, rgba($color-dark, 0.3) 38%, $color-background 54%);
background-size: 1000px 100%;
animation: loading 1s infinite linear;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: $padding;
right: $padding;
bottom: $padding;
left: $padding;
border-radius: calc($border-radius-large - $padding);
background-color: rgba($color-background, 0.9);
}
&.title {
margin-bottom: $spacing-small;
height: calc($font-size-h1 + 10px);
width: 150px;
}
&.price {
margin-bottom: $spacing-normal;
height: calc($font-size-h2 + 10px);
width: 60px;
}
&.description {
height: 400px;
width: 100%;
}
}
@media only screen and (max-width: 670px) {
.announcement-banner-loading {
margin: -$spacing-small;
margin-bottom: 0;
height: 250px;
}
}
@keyframes loading{
0%{
background-position: -500px 0
}
100%{
background-position: 500px 0
}
}
</style> </style>

View file

@ -1,6 +1,8 @@
import { wrap } from "svelte-spa-router/wrap"; import { wrap } from "svelte-spa-router/wrap";
import PageLoading from "%/pages/PageLoading.svelte"; import PageLoading from "%/pages/PageLoading.svelte";
import Page404 from "%/pages/Page404.svelte"; import Page404 from "%/pages/Page404.svelte";
import Page500 from "%/pages/Page500.svelte";
const routes = { const routes = {
"/": wrap({ "/": wrap({
@ -15,7 +17,7 @@ const routes = {
conditions: [], conditions: [],
userData: { showNavBar: true, fullWidth: true, }, userData: { showNavBar: true, fullWidth: true, },
}), }),
"/item/:name": wrap({ "/item/:uuid": wrap({
asyncComponent: () => import("%/pages/PageItem.svelte"), asyncComponent: () => import("%/pages/PageItem.svelte"),
loadingComponent: PageLoading, loadingComponent: PageLoading,
conditions: [], conditions: [],
@ -39,11 +41,21 @@ const routes = {
conditions: [], conditions: [],
userData: { showNavBar: true, fullWidth: false, }, userData: { showNavBar: true, fullWidth: false, },
}), }),
'*': wrap({ "/ForOhFor": wrap({
component: Page404, component: Page404,
conditions: [], conditions: [],
userData: { showNavBar: true, fullWidth: false, }, userData: { showNavBar: true, fullWidth: false, },
}) }),
"/ServerError": wrap({
component: Page500,
conditions: [],
userData: { showNavBar: true, fullWidth: false, },
}),
"*": wrap({
component: Page404,
conditions: [],
userData: { showNavBar: true, fullWidth: false, },
}),
} }
export default routes; export default routes;