Merge branch '22-integrate-api-and-frontend' into 36-refactor-dataset-class

This commit is contained in:
Elias Schriefer
2024-07-05 17:04:58 +02:00
21 changed files with 82 additions and 113 deletions

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DataDash – Add dataset/API</title>
<link rel="stylesheet" href="add.css">
<script type="module" src="add.js"></script>
</head>
<body>
<main>
<header>
<h1>Add new DataDash content</h1>
</header>
<section>
<p>
Please add the following information about your dataset/API to
help users better find it and understand what it is about and
how to use it.
</p>
<form>
<span>
<label for="title">Title</label>
<input type="text" name="title" id="title" minlength="1" maxlength="50" required>
</span>
<span id="author-box">
<label for="author">Author</label>
<input type="text" name="author" id="author" required>
</span>
<label>
Dataset
<input type="checkbox" name="is-dataset" id="is-dataset">
<span id="is-dataset-toggle"></span>
API
</label>
<span>
<label for="short-description">Short description</label>
<input type="text" name="short-description" id="short-description" maxlength="100" required spellcheck="true">
</span>
<span>
<label for="url">URL</label>
<input type="url" name="url" id="url" required>
</span>
<span id="full-description-box">
<label for="full-description">Full description</label>
<textarea name="full-description" id="full-description" spellcheck="true"></textarea>
</span>
<span id="btn-bar">
<input type="submit" value="Add" id="btn-add" class="btn suggested" disabled>
<input type="reset" value="Cancel" id="btn-cancel" class="btn">
</span>
</form>
</section>
</main>
</body>
</html>

View File

@@ -20,10 +20,12 @@ function parseContent(content, clearResults) {
if (content.length === 0) {
nothingFoundElement.classList.remove("hidden");
searchSection.querySelector(".datasets").classList.add("hidden");
} else {
nothingFoundElement.classList.add("hidden");
const datasets = content.map(dataset => Dataset.get(dataset.id) ?? new Dataset(dataset));
searchSection.querySelector(".datasets").classList.remove("hidden");
if (clearResults) {
Array.from(searchSection.querySelectorAll(".datasets .dataset")).forEach(e => e.remove());
}

View File

@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DataDash</title>
<link rel="stylesheet" href="main.css">
<script type="module" src="main.js" defer></script>
</head>
<body>
<div id="add-btn" title="Add a new API entry"></div>
<main>
<header>
<h1>Welcome to DataDash</h1>
<p>The place to launch and discover datasets and API endpoints.</p>
</header>
<template id="dataset-template">
<li class="dataset" data-id="id">
<div class="dataset-info">
<div class="details">
<h3 class="dataset-title">title</h3>
<p class="dataset-description">Simply daily accountability phone call, powered by AI</p>
</div>
</div>
<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>
</li>
</template>
<section id="tool-bar">
<button class="btn flat" id="reset-tools-btn" title="Reset search results">Reset</button>
<select id="sort-btn" class="btn flat" title="Sort entries">Sort by
<option id="default-sort">Date newest-oldest</option>
<option>Date oldest-newest</option>
<option>Author A-Z</option>
<option>Author Z-A</option>
<option>Title A-Z</option>
<option>Title Z-A</option>
<option>Stars ↑</option>
<option>Stars ↓</option>
<option>Upvotes ↑</option>
<option>Upvotes ↓</option>
</select>
<div class="divider"></div>
<select class="btn flat" id="filter-btn" title="Filter entries">Filter
<option id="default-filter">None</option>
<optgroup label="Standard categories">
<option>Dataset</option>
<option>API</option>
</optgroup>
<optgroup id="other-categories" label="Other categories">
</optgroup>
</select>
<input type="search" name="query" id="search-entry" placeholder="Search">
<button class="btn flat" id="search-btn" title="Search entries">Search</button>
</section>
<section id="recents">
<h2>Recently added:</h2>
<ul class="datasets">
</ul>
</section>
<section id="top">
<h2>Most Liked:</h2>
<ul class="datasets">
</ul>
</section>
<section id="search" class="hidden">
<h2>Search results:</h2>
<div id="nothing-found">
<div id="nothing-found-bg"></div>
<h3 id="nothing-found-text">Nothing found</h3>
</div>
<ul class="datasets">
</ul>
<div id="observable" style="height: 2rem"></div>
</section>
</main>
</body>
</html>

View File

@@ -78,10 +78,6 @@ header {
text-align: center;
}
.hidden {
display: none;
}
#search-entry:focus-visible {
outline: none;
}
@@ -93,6 +89,11 @@ header {
gap: 1rem;
}
.hidden {
display: none;
}
@container (width < 60ch) {
.datasets {
grid-template-columns: 1fr;

View File

@@ -9,6 +9,7 @@ export const lastQuery = {
totalPages: 0,
currentPage: 0,
};
const loadedCategories = new Set;
// definition of all buttons & sections
const addButton = document.getElementById("add-btn");
@@ -33,22 +34,23 @@ addButton.addEventListener("click", () => {
});
filterButton.addEventListener("change", () => {
const filterString = filterButton.value;
if (filterString !== filterButton.querySelector("#default-filter").value) {
fetchQuery(createQuery(), true);
}
fetchQuery(createQuery(), true);
});
filterButton.addEventListener("click", () => {
fetchCategories();
})
searchButton.addEventListener("click", () => {
fetchQuery(createQuery(), true);
});
searchBar.addEventListener("input", () => {
updateSections();
clearTimeout(searchBarTimeout);
searchBarTimeout = setTimeout(() => {
fetchQuery(createQuery(), true);
updateSections();
}, searchDelay);
});
@@ -71,7 +73,7 @@ resetButton.addEventListener("click", () => {
// functions of the main page
function navigateToAdd() {
window.location.href = "/add"; //TODO: move to EventListner?
window.location.href = "/add.html"; //TODO: move to EventListener?
}
function getFilterQuery() {
@@ -81,7 +83,7 @@ function getFilterQuery() {
} else if (document.querySelector('#filter-btn option:checked').parentElement.label === "Standard categories") {
return ["type", filterString];
} else {
return ["category", filterString];
return ["category", filterButton.options[filterButton.selectedIndex].value]
}
}
@@ -135,15 +137,18 @@ function updateSections() {
// fetches the further categories used in the filter function
function fetchCategories() {
const fetchURL = new URL(
"api/v1/categories", getBaseURL());
const fetchURL = new URL("api/v1/categories", getBaseURL());
fetch(fetchURL)
.then(resp => resp.json())
.then((data) => {
for (let i = 0; i < data.length; i++) {
let category = data[i].toLowerCase();
category = category.charAt(0).toUpperCase() + category.slice(1);
document.getElementById("other-categories").appendChild(new Option(category));
let categoryName = data[i].name.toLowerCase();
categoryName = categoryName.charAt(0).toUpperCase() + categoryName.slice(1);
if (!loadedCategories.has(categoryName)) {
let newCategory = new Option(categoryName, data[i].id);
document.getElementById("other-categories").appendChild(newCategory);
loadedCategories.add(categoryName);
}
}
});
}