Merge branch '7-add-page-to-view-dataset-api' into 43-store-entry-authorship

got code from 7 in order to further implement 43
This commit is contained in:
J-Klinke 2024-07-06 14:04:31 +02:00
commit bd854ff016
10 changed files with 474 additions and 33 deletions

View File

@ -1,9 +1,5 @@
@import url("main.css"); @import url("main.css");
:root {
--accent-color: oklch(65.33% 0.158 247.76);
}
form { form {
display: grid; display: grid;
grid-template-columns: 1fr 1fr auto; grid-template-columns: 1fr 1fr auto;

View File

@ -0,0 +1,2 @@
export const DATASET_ENDPOINT = "/api/v1/datasets";
export const getBaseURL = () => location.origin;

View File

@ -1,13 +1,13 @@
import { DATASET_ENDPOINT, getBaseURL } from "./main.js"; import { DATASET_ENDPOINT, getBaseURL } from "./constants.js";
export default class Dataset { export default class Dataset {
static #datasets = new Map(); static #datasets = new Map();
#abstract; #shortDescription;
#author; #author;
#categories; #category;
#date; #date;
#description; #fullDescription;
#id; #id;
#rating; #rating;
#title; #title;
@ -15,48 +15,52 @@ export default class Dataset {
#upvotes; #upvotes;
#url; #url;
#votes; #votes;
#license;
#termsOfUse;
#elements = []; #elements = [];
static get(id) { static get(id) {
return this.#datasets.get(id); return this.#datasets.get(id);
} }
constructor({ abst: shortDescription, author, categories, date, description, id, rating, title, type, upvotes, url, votes }) { constructor({ abst: shortDescription, author, categorie, date, description, id, raiting, title, type, upvotes, url, votes, license, termsOfUse }) {
this.#abstract = shortDescription; this.#shortDescription = shortDescription;
this.#author = author; this.#author = author;
this.#categories = categories; this.#category = categorie;
this.#date = date; this.#date = date;
this.#description = description; this.#fullDescription = description;
this.#id = id; this.#id = id;
this.#rating = rating; this.#rating = raiting;
this.#title = title; this.#title = title;
this.#type = type; this.#type = type;
this.#upvotes = upvotes; this.#upvotes = upvotes;
this.#url = url; this.#url = url;
this.#votes = votes; this.#votes = votes;
this.#license = license;
this.#termsOfUse = termsOfUse;
Dataset.#datasets.set(id, this); Dataset.#datasets.set(id, this);
} }
// Getters // Getters
get abstract() { get shortDescription() {
return this.#abstract; return this.#shortDescription;
} }
get author() { get author() {
return this.#author; return this.#author;
} }
get categories() { get category() {
return this.#categories; return this.#category;
} }
get date() { get date() {
return this.#date; return this.#date;
} }
get description() { get fullDescription() {
return this.#description; return this.#fullDescription;
} }
get id() { get id() {
@ -87,6 +91,14 @@ export default class Dataset {
return this.#votes; return this.#votes;
} }
get license() {
return this.#license;
}
get termsOfUse() {
return this.#termsOfUse;
}
get mainElement() { get mainElement() {
return this.#elements[0]; return this.#elements[0];
} }
@ -95,6 +107,10 @@ export default class Dataset {
return this.#elements; return this.#elements;
} }
parseDate() {
return new Date(this.#date);
}
// Main methods // Main methods
// Only on main page // Only on main page
@ -114,7 +130,7 @@ export default class Dataset {
} }
}) })
clone.querySelector(".dataset-title").innerText = this.#title; clone.querySelector(".dataset-title").innerText = this.#title;
clone.querySelector(".dataset-description").innerText = this.#description; clone.querySelector(".dataset-description").innerText = this.#shortDescription;
clone.querySelector(".upvote-count").innerText = this.#upvotes; clone.querySelector(".upvote-count").innerText = this.#upvotes;
this.#elements.push(clone.children[0]); this.#elements.push(clone.children[0]);

View File

@ -0,0 +1,180 @@
@import url("./main.css");
@import url('https://fonts.googleapis.com/css2?family=Flow+Circular&display=swap');
:root {
--min-card-size: min(60ch, calc(100vw - var(--pad-main)));
--rating-color: gold;
}
main {
& > :is(header, section, footer) {
background-color: var(--fg-color);
padding: var(--pad-datasets-block) var(--pad-datasets-inline);
position: relative;
}
& > :first-child {
border-radius: var(--corner-radius) var(--corner-radius) 0 0;
margin-top: var(--pad-main);
}
& > :last-child {
border-radius: 0 0 var(--corner-radius) var(--corner-radius);
margin-bottom: var(--pad-main);
}
& > :not(:last-child):is(header, section)::after {
content: '';
position: absolute;
inset-inline: calc(var(--pad-datasets-inline) - var(--gap-small));
bottom: 0;
border-bottom: 3px solid var(--bg-color);
opacity: .25;
transform: translateY(50%);
z-index: 1;
}
}
header {
margin-inline: 0;
display: grid;
grid-template-columns: 1fr 1fr max-content;
align-items: center;
grid-gap: var(--gap-medium);
}
#title {
grid-column: 1 / 3;
margin-block: var(--gap-medium) 0;
text-align: center;
&::after {
content: attr(data-type);
background-color: var(--accent-color);
font-size: .5em;
font-weight: initial;
position: relative;
bottom: .25lh;
margin-inline: var(--gap-small);
padding: 2pt 4pt;
border-radius: 4pt;
}
&[data-type="dataset"]::after {
content: "Dataset";
}
&[data-type="api"]::after {
content: "API";
}
}
:has(#rating), #url {
text-align: start;
grid-column: 1 / 3;
}
#rating {
color: color-mix(in oklab, var(--text-color) 80%, black);
}
#rating::after {
content: "";
display: inline-block;
width: 5em;
height: 1lh;
vertical-align: bottom;
margin-inline: .5ch;
mask-image: url("stars.svg");
-webkit-mask-image: url("stars.svg");
mask-size: 100% 100%;
mask-mode: alpha;
--rating-percent: calc((var(--rating, 0) / 5) * 100%);
background: linear-gradient(to right, var(--rating-color) var(--rating-percent), var(--bg-color) var(--rating-percent));
}
a {
--text-color: var(--accent-color);
/*
Why doesn't it do this automatically? It is inherited from body,
so I should be able to just change --text-color, right?
*/
color: var(--text-color);
}
#terms-of-use {
/* text-align: end; */
}
.upvote {
margin: var(--gap-medium) 0;
align-self: self-start;
grid-column: 3;
grid-row: 1 / 4;
}
#metadata {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
gap: var(--gap-large);
}
#full-description {
text-wrap: balance;
text-wrap: pretty;
margin-top: 0;
br {
margin-bottom: .5lh;
}
}
.skeleton {
font-family: "Flow Circular";
font-weight: 400;
font-style: normal;
user-select: none;
--rating-color: var(--text-color);
a, .btn {
pointer-events: none;
}
& > * {
cursor: progress;
}
@media screen and not (prefers-reduced-motion) {
:is(header, section) > :is(p, span, h1, a) {
animation: infinite 2s linear skeleton-loading;
background: radial-gradient(
circle farthest-side,
var(--highlight-color, white) 20%,
var(--text-color) 40%
) no-repeat, var(--text-color);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
&:is(a) {
--highlight-color: color-mix(in oklab, white, var(--text-color));
}
}
}
#title::after {
color: color-mix(in oklab, var(--accent-color) 50%, currentcolor);
}
}
@keyframes skeleton-loading {
from {
background-position-x: calc(-1.4 * var(--min-card-size)), 0;
}
to {
background-position-x: calc(1.4 * var(--min-card-size)), 0;
}
}

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dataset details</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Flow+Circular&display=swap" crossorigin>
<link rel="stylesheet" href="details.css">
<script defer type="module" src="details.js"></script>
</head>
<body>
<template id="voting-template">
<aside class="upvote">
<button class="upvote-btn btn flat">Upvote</button>
<span class="upvote-count">0</span>
<button class="downvote-btn btn flat">Downvote</button>
</aside>
</template>
<main class="skeleton">
<header data-id="dataset-id">
<h1 id="title" data-type="api">Title</h1>
<span>
<span id="rating" style="--rating: 4">4</span>
<span id="short-description">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis recusandae laborum odio corrupti voluptas quisquam dicta, quibusdam ipsum qui exercitationem.</span>
</span>
<a id="url">https://example.com/dataset</a>
<aside class="upvote">
<button disabled class="upvote-btn btn flat">Upvote</button>
<span class="upvote-count">0</span>
<button disabled class="downvote-btn btn flat">Downvote</button>
</aside>
</header>
<section id="metadata">
<span>Added on: <span id="date" data-date="0">1. January 1970</span></span>
<span>Category: <span id="category">Something</span></span>
<span>License: <span id="license">MIT</span></span>
<a id="terms-of-use">Terms of Use</a>
</section>
<section id="details">
<p id="full-description">Full description<br>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Beatae
nihil saepe et numquam quo id voluptatum recusandae assumenda
doloremque pariatur consequatur molestias delectus dolore
corrupti, odio modi vitae repellat tempora sed eos voluptates
temporibus veritatis repudiandae. Cum eveniet molestias, in
beatae non reiciendis quia voluptatem id, facere architecto
vitae harum ipsum earum deleniti dolor atque recusandae odit
corporis error dolorum blanditiis vel maxime pariatur quibusdam!
<br>Saepe debitis ab possimus, dolorem neque ad voluptatibus ex
quisquam itaque. Nihil et non consequuntur error ipsa.
Necessitatibus voluptatibus aliquid itaque id ipsum, pariatur
odio explicabo, dolores ex, incidunt tenetur dolore. Assumenda
ipsam nobis quis.
</p>
</section>
</main>
</body>
</html>

View File

@ -0,0 +1,51 @@
import Dataset from "./dataset.js";
const mainElement = document.getElementsByTagName("main")[0];
const title = document.getElementById("title");
const rating = document.getElementById("rating");
const shortDescription = document.getElementById("short-description");
const url = document.getElementById("url");
const date = document.getElementById("date");
const category = document.getElementById("category");
const license = document.getElementById("license");
const termsOfUse = document.getElementById("terms-of-use");
const fullDescription = document.getElementById("full-description");
const currentLocation = new URL(location.href);
if (currentLocation.searchParams.has("id")) {
const id = currentLocation.searchParams.get("id");
const response = await fetch(`${currentLocation.origin}/api/v1/datasets/id/${id}`);
console.dir(response);
if (response.ok) {
const data = await response.json();
const dataset = new Dataset(data);
console.dir(data, dataset);
const upvoteComponent = dataset.createUpvoteComponent();
title.innerText = dataset.title;
title.dataset.type = dataset.type.toLowerCase();
rating.innerText = dataset.rating;
rating.style.setProperty("--rating", `${dataset.rating}`);
shortDescription.innerText = dataset.shortDescription;
url.href = dataset.url;
url.innerText = dataset.url;
mainElement.querySelector(".upvote").replaceWith(upvoteComponent);
date.innerText = dataset.parseDate().toLocaleDateString(undefined, {
day: "numeric",
month: "long",
year: "numeric",
});
date.dataset.date = dataset.parseDate().getTime();
category.innerText = dataset.category.name;
category.dataset.id = dataset.category.id;
license.innerText = dataset.license;
termsOfUse.href = dataset.termsOfUse;
fullDescription.innerText = dataset.fullDescription;
mainElement.classList.remove("skeleton");
}
}

View File

@ -4,6 +4,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DataDash</title> <title>DataDash</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="prefetch" href="https://fonts.googleapis.com/css2?family=Flow+Circular&display=swap">
<link rel="stylesheet" href="main.css"> <link rel="stylesheet" href="main.css">
<script type="module" src="main.js" defer></script> <script type="module" src="main.js" defer></script>
</head> </head>

View File

@ -2,7 +2,12 @@
--bg-color: #222; --bg-color: #222;
--fg-color: #555; --fg-color: #555;
--text-color: #dbdbdb; --text-color: #dbdbdb;
--pad-datasets: 1rem; --accent-color: oklch(65.33% 0.158 247.76);
--pad-datasets-block: 1rem;
--pad-datasets-inline: 2rem;
--gap-large: 1.5rem;
--gap-medium: 1rem;
--gap-small: .5rem;
--pad-main: 2rem; --pad-main: 2rem;
--min-card-size: min(60ch, 33vw); --min-card-size: min(60ch, 33vw);
--corner-radius: 1rem; --corner-radius: 1rem;
@ -17,7 +22,7 @@ body {
} }
main { main {
max-width: calc(2 * var(--min-card-size) + var(--pad-main) + var(--pad-datasets)); max-width: calc(2 * var(--min-card-size) + var(--pad-main) + 2 * var(--pad-datasets-inline));
padding-inline: var(--pad-main); padding-inline: var(--pad-main);
margin-inline: auto; margin-inline: auto;
container-type: inline-size; container-type: inline-size;
@ -47,12 +52,12 @@ header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
float: right; float: right;
gap: .5rem; gap: var(--gap-small);
background-color: var(--fg-color, darkgrey); background-color: var(--fg-color, darkgrey);
padding: .5rem 1rem; padding: .5rem 1rem;
margin-bottom: var(--pad-datasets); margin-bottom: var(--pad-datasets-block);
margin-left: var(--pad-datasets); margin-left: var(--pad-datasets-inline);
margin-right: var(--pad-datasets); margin-right: var(--pad-datasets-inline);
border-radius: 1.5rem; border-radius: 1.5rem;
} }
@ -83,10 +88,10 @@ header {
} }
.datasets { .datasets {
padding-inline: var(--pad-datasets); padding-inline: var(--pad-datasets-inline);
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(var(--min-card-size), 1fr)); grid-template-columns: repeat(auto-fit, minmax(var(--min-card-size), 1fr));
gap: 1rem; gap: var(--gap-medium);
} }
.hidden { .hidden {
@ -101,7 +106,7 @@ header {
} }
.dataset { .dataset {
padding: var(--pad-datasets) 2rem; padding: var(--pad-datasets-block) var(--pad-datasets-inline);
background-color: var(--fg-color, darkgrey); background-color: var(--fg-color, darkgrey);
border-radius: var(--corner-radius); border-radius: var(--corner-radius);
list-style: none; list-style: none;
@ -122,7 +127,7 @@ header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: .5em; gap: var(--gap-small);
} }
/* Buttons */ /* Buttons */

View File

@ -1,9 +1,7 @@
import { DATASET_ENDPOINT, getBaseURL } from "./constants.js";
import { fetchQuery } from "./contentUtility.js"; import { fetchQuery } from "./contentUtility.js";
import Dataset from "./dataset.js"; import Dataset from "./dataset.js";
export const DATASET_ENDPOINT = "/api/v1/datasets";
export const getBaseURL = () => location.origin;
const defaultPagingValue = 20; const defaultPagingValue = 20;
export const lastQuery = { export const lastQuery = {
totalPages: 0, totalPages: 0,

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
width="4.52333in" height="0.853333in"
viewBox="0 0 1357 256">
<path id="Selection"
fill="black" stroke="black" stroke-width="1"
d="M 145.00,19.00
C 148.26,23.95 151.83,34.12 154.20,40.00
154.20,40.00 167.00,71.00 167.00,71.00
168.58,74.95 174.23,90.23 176.65,92.40
178.81,94.36 189.75,94.96 193.00,95.00
193.00,95.00 256.00,98.00 256.00,98.00
252.97,103.56 245.88,108.30 241.00,112.42
241.00,112.42 212.00,137.08 212.00,137.08
209.10,139.50 197.48,148.71 196.46,151.43
195.50,153.97 199.97,168.40 200.87,172.00
200.87,172.00 216.00,229.00 216.00,229.00
216.00,229.00 168.00,199.95 168.00,199.95
164.08,197.50 150.78,188.29 147.00,188.29
143.53,188.30 130.58,197.29 127.00,199.67
127.00,199.67 79.00,230.00 79.00,230.00
79.00,230.00 92.79,173.00 92.79,173.00
92.79,173.00 96.68,152.17 96.68,152.17
96.68,152.17 80.00,137.39 80.00,137.39
80.00,137.39 52.00,114.42 52.00,114.42
52.00,114.42 36.00,100.00 36.00,100.00
36.00,100.00 92.00,96.09 92.00,96.09
96.36,95.79 111.98,95.53 114.78,93.40
118.14,90.85 122.99,76.57 124.68,72.00
124.68,72.00 145.00,19.00 145.00,19.00 Z
M 411.00,19.00
C 414.26,23.95 417.83,34.12 420.20,40.00
420.20,40.00 433.00,71.00 433.00,71.00
434.58,74.95 440.23,90.23 442.65,92.40
444.81,94.36 455.75,94.96 459.00,95.00
459.00,95.00 522.00,98.00 522.00,98.00
518.97,103.56 511.88,108.30 507.00,112.42
507.00,112.42 478.00,137.08 478.00,137.08
475.10,139.50 463.48,148.71 462.46,151.43
461.50,153.97 465.97,168.40 466.87,172.00
466.87,172.00 482.00,229.00 482.00,229.00
482.00,229.00 434.00,199.95 434.00,199.95
430.08,197.50 416.78,188.29 413.00,188.29
409.53,188.30 396.58,197.29 393.00,199.67
393.00,199.67 345.00,230.00 345.00,230.00
345.00,230.00 358.79,173.00 358.79,173.00
358.79,173.00 362.68,152.17 362.68,152.17
362.68,152.17 346.00,137.39 346.00,137.39
346.00,137.39 318.00,114.42 318.00,114.42
318.00,114.42 302.00,100.00 302.00,100.00
302.00,100.00 358.00,96.09 358.00,96.09
362.36,95.79 377.98,95.53 380.78,93.40
384.14,90.85 388.99,76.57 390.68,72.00
390.68,72.00 411.00,19.00 411.00,19.00 Z
M 678.00,19.00
C 681.26,23.95 684.83,34.12 687.20,40.00
687.20,40.00 700.00,71.00 700.00,71.00
701.58,74.95 707.23,90.23 709.65,92.40
711.81,94.36 722.75,94.96 726.00,95.00
726.00,95.00 789.00,98.00 789.00,98.00
785.97,103.56 778.88,108.30 774.00,112.42
774.00,112.42 745.00,137.08 745.00,137.08
742.10,139.50 730.48,148.71 729.46,151.43
728.50,153.97 732.97,168.40 733.87,172.00
733.87,172.00 749.00,229.00 749.00,229.00
749.00,229.00 701.00,199.95 701.00,199.95
697.08,197.50 683.78,188.29 680.00,188.29
676.53,188.30 663.58,197.29 660.00,199.67
660.00,199.67 612.00,230.00 612.00,230.00
612.00,230.00 625.79,173.00 625.79,173.00
625.79,173.00 629.68,152.17 629.68,152.17
629.68,152.17 613.00,137.39 613.00,137.39
613.00,137.39 585.00,114.42 585.00,114.42
585.00,114.42 569.00,100.00 569.00,100.00
569.00,100.00 625.00,96.09 625.00,96.09
629.36,95.79 644.98,95.53 647.78,93.40
651.14,90.85 655.99,76.57 657.68,72.00
657.68,72.00 678.00,19.00 678.00,19.00 Z
M 944.00,19.00
C 947.26,23.95 950.83,34.12 953.20,40.00
953.20,40.00 966.00,71.00 966.00,71.00
967.58,74.95 973.23,90.23 975.65,92.40
977.81,94.36 988.75,94.96 992.00,95.00
992.00,95.00 1055.00,98.00 1055.00,98.00
1051.97,103.56 1044.88,108.30 1040.00,112.42
1040.00,112.42 1011.00,137.08 1011.00,137.08
1008.10,139.50 996.48,148.71 995.46,151.43
994.50,153.97 998.97,168.40 999.87,172.00
999.87,172.00 1015.00,229.00 1015.00,229.00
1015.00,229.00 967.00,199.95 967.00,199.95
963.08,197.50 949.78,188.29 946.00,188.29
942.53,188.30 929.58,197.29 926.00,199.67
926.00,199.67 878.00,230.00 878.00,230.00
878.00,230.00 891.79,173.00 891.79,173.00
891.79,173.00 895.68,152.17 895.68,152.17
895.68,152.17 879.00,137.39 879.00,137.39
879.00,137.39 851.00,114.42 851.00,114.42
851.00,114.42 835.00,100.00 835.00,100.00
835.00,100.00 891.00,96.09 891.00,96.09
895.36,95.79 910.98,95.53 913.78,93.40
917.14,90.85 921.99,76.57 923.68,72.00
923.68,72.00 944.00,19.00 944.00,19.00 Z
M 1211.00,19.00
C 1214.26,23.95 1217.83,34.12 1220.20,40.00
1220.20,40.00 1233.00,71.00 1233.00,71.00
1234.58,74.95 1240.23,90.23 1242.65,92.40
1244.81,94.36 1255.75,94.96 1259.00,95.00
1259.00,95.00 1322.00,98.00 1322.00,98.00
1318.97,103.56 1311.88,108.30 1307.00,112.42
1307.00,112.42 1278.00,137.08 1278.00,137.08
1275.10,139.50 1263.48,148.71 1262.46,151.43
1261.50,153.97 1265.97,168.40 1266.87,172.00
1266.87,172.00 1282.00,229.00 1282.00,229.00
1282.00,229.00 1234.00,199.95 1234.00,199.95
1230.08,197.50 1216.78,188.29 1213.00,188.29
1209.53,188.30 1196.58,197.29 1193.00,199.67
1193.00,199.67 1145.00,230.00 1145.00,230.00
1145.00,230.00 1158.79,173.00 1158.79,173.00
1158.79,173.00 1162.68,152.17 1162.68,152.17
1162.68,152.17 1146.00,137.39 1146.00,137.39
1146.00,137.39 1118.00,114.42 1118.00,114.42
1118.00,114.42 1102.00,100.00 1102.00,100.00
1102.00,100.00 1158.00,96.09 1158.00,96.09
1162.36,95.79 1177.98,95.53 1180.78,93.40
1184.14,90.85 1188.99,76.57 1190.68,72.00
1190.68,72.00 1211.00,19.00 1211.00,19.00 Z" />
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB