Merge branch '22-integrate-api-and-frontend' into 36-refactor-dataset-class
This commit is contained in:
64
src/main/resources/static/add.html
Normal file
64
src/main/resources/static/add.html
Normal 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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
85
src/main/resources/static/index.html
Normal file
85
src/main/resources/static/index.html
Normal 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>
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user