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'},
}
let windowScrollY = 0;
let windowWidth = 0;
let scrollY = 0;
let width = 0;
let oldLocation = undefined;
let fullWidth = false;
let showNavBar = false;
$: scrolled = windowScrollY > 0
$: mobile = windowWidth < 700
function routeLoading(event) {
if (event.detail.location === oldLocation) {
console.log("Fake!");
return; // not an actual change
}
showNavBar = event.detail.userData.showNavBar;
fullWidth = event.detail.userData.fullWidth;
oldLocation = event.detail.location;
@ -38,15 +37,18 @@
}
</script>
<svelte:window bind:scrollY={windowScrollY} bind:innerWidth={windowWidth} />
<svelte:window
bind:scrollY={scrollY}
bind:innerWidth={width}
/>
<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">
</svelte:head>
{#if showNavBar }
<nav class:scrolled={scrolled} class:mobile={mobile}>
{#if !mobile}
<nav class:scrolled={scrollY > 0} class:mobile={width < 700}>
{#if !(width < 700)}
<ul style="justify-content: flex-end">
<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>

View file

@ -6,9 +6,7 @@
{#await announcement}
<div class="announcement-banner-loading">
<div />
</div>
<div class="announcement-banner-loading" />
{:then announcement}
<div class="announcement-banner">
<img src={announcement.image} alt="">
@ -35,12 +33,15 @@
overflow: hidden;
> div {
&::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);
}

View file

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

View file

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

View file

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

View file

@ -1,19 +1,32 @@
import Items from '%/lib/test-data.js';
let cache = {};
async function fakeDelay(timeout = 1000) {
await new Promise(resolve => setTimeout(resolve, timeout));
}
export async function getAnnouncements() {
if (cache.announcement_banner !== undefined) {
return cache.announcement_banner;
}
const data = {
image: "/BannerExampleImage.jpg",
};
await fakeDelay(2000)
cache.announcement_banner = data;
await fakeDelay(5000)
return data;
}
export async function getPopularToday() {
if (cache.popular_today !== undefined) {
return cache.popular_today;
}
const data = Items;
cache.popular_today = data;
await fakeDelay(2000)
return data;
}
@ -33,6 +46,24 @@ export async function getMenuItems() {
items: Items,
},
];
await fakeDelay(2000)
await fakeDelay(20)
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",
price: 69.99,
labels: ["vegan", "spicy"],
detail: "Example",
},
// sock: {
{
@ -14,6 +15,7 @@ const Items = [
name: "Sock",
price: 21,
labels: ["vegan", "fish", "nut", "spicy"],
detail: "Example",
},
// brick: {
{
@ -21,6 +23,7 @@ const Items = [
name: "Brick",
price: 0,
labels: ["spicy"],
detail: "Example",
},
// toast: {
{
@ -28,6 +31,7 @@ const Items = [
name: "Toast",
price: 4382749832743,
labels: ["gluten"],
detail: "Example",
},
// water: {
{
@ -35,6 +39,7 @@ const Items = [
name: "water",
price: 1,
labels: ["fish"],
detail: "Example",
},
// mouldy_bread: {
{
@ -42,6 +47,7 @@ const Items = [
name: "half eaten mouldy bread",
price: -99,
labels: ["nut"],
detail: "Example",
},
// gwagwa: {
{
@ -58,6 +64,7 @@ const Items = [
price: "1111",
labels: ["fish"],
image: "/wathog.jpg",
detail: "Example",
},
// bluhog: {
{
@ -66,6 +73,7 @@ const Items = [
price: "ARUGH",
labels: ["nut", "gluten", "spicy"],
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;
max-width: calc(100vw - calc(2 * $spacing-normal));
resize: none;
overflow: hidden;
}
button {

View file

@ -1,95 +1,161 @@
<script>
import { replace } from "svelte-spa-router";
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 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>
<div class="main">
<div class="images">
<div>
<img src={LoadingImage} alt="">
{#await item}
<div id="images">
<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>
<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 class="info">
<h2>{params.name}</h2>
</div>
<div id="info">
<div class="loading title" />
<div class="loading price" />
<div class="loading description" />
</div>
{:then item}
<div id="images">
<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 class="spacer"></div>
<div class="other">
<h2>Popular</h2>
<MenuList items={items} />
<div id="popular">
{#await popularToday}
<LoadingBar />
{:then items}
<MenuList {items} />
{:catch error}
<p>{error}</p>
{/await}
</div>
</div>
<style lang="scss">
@import "%/styles/vars";
h2 {
margin-bottom: $spacing-small;
}
.spacer {
height: $spacing-large;
}
$padding: 1px;
.main {
display: flex;
flex-direction: row;
}
#images {
display: flex;
flex-direction: column;
> div {
margin-bottom: $spacing-small;
width: 650px;
height: 500px;
.images {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
> div {
margin-bottom: $spacing-small;
overflow: hidden;
width: 650px;
height: 500px;
> img {
max-width: 650px;
max-height: 500px;
display: flex;
justify-content: center;
align-items: center;
border-radius: $border-radius-normal;
}
}
//border-radius: $border-radius-large;
//background-color: $color-light;
> ul {
margin: 0;
padding: 0;
overflow: hidden;
display: flex;
flex-direction: row;
> li {
list-style: none;
> img {
max-width: 650px;
max-height: 500px;
margin-right: $spacing-small;
width: 100px;
border-radius: $border-radius-normal;
}
}
}
}
> ul {
margin: 0;
padding: 0;
#info {
width: 100%;
display: flex;
flex-direction: row;
display: flex;
flex-direction: column;
align-items: flex-end;
> li {
list-style: none;
> img {
margin-right: $spacing-small;
width: 100px;
border-radius: $border-radius-normal;
}
}
}
> h2 {
font-size: $font-size-h1;
padding-bottom: $spacing-small;
}
> p {
font-size: $font-size-h2;
padding-bottom: $spacing-normal;
}
.container {
padding: $spacing-normal;
width: 100%;
}
}
@ -97,4 +163,65 @@
margin: 0 auto;
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>

View file

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