Add common button styling

This commit is contained in:
Elias Schriefer
2024-07-08 01:25:07 +02:00
parent 1888b91afe
commit 3fcb100199
7 changed files with 174 additions and 176 deletions

View File

@@ -43,7 +43,7 @@ form :is(input[type=text], input[type=url], textarea) {
outline: 2px solid var(--accent-color); outline: 2px solid var(--accent-color);
} }
.btn, #is-dataset-toggle { #is-dataset-toggle {
transition: outline ease-in 100ms; transition: outline ease-in 100ms;
} }
@@ -150,51 +150,10 @@ form :has(#url) {
} }
/* button styling */ /* button styling */
.btn { #is-dataset:focus-visible + #is-dataset-toggle {
padding: .5lh 1lh;
border: none;
border-radius: .5lh;
--btn-color: var(--fg-color);
background-color: var(--btn-color);
color: var(--text-color);
font-weight: bold;
font-size: 1rem;
transition: background-color 100ms, filter 200ms;
transition-timing-function: ease-out;
--drop-shadow-opacity: .5;
--drop-shadow-offset-y: 0;
--drop-shadow-blur: .25rem;
--drop-shadow: drop-shadow(
rgba(0, 0, 0, var(--drop-shadow-opacity))
0 var(--drop-shadow-offset-y) var(--drop-shadow-blur)
);
filter: var(--drop-shadow);
}
.btn:focus-visible, #is-dataset:focus-visible + #is-dataset-toggle {
outline-offset: 2px; outline-offset: 2px;
} }
.btn:not(:disabled):hover {
background-color: color-mix(in oklab, var(--btn-color) 80%, var(--bg-color));
--drop-shadow-opacity: .8;
--drop-shadow-offset-y: .25rem;
--drop-shadow-blur: .4rem;
}
.btn.suggested {
--btn-color: var(--accent-color);
}
.btn:disabled {
filter: var(--drop-shadow) grayscale(.5) brightness(.5);
}
.btn.full-width {
width: -moz-available;
width: -webkit-fill-available;
}
#category[value="new"] { #category[value="new"] {
display: none; display: none;
} }

View File

@@ -0,0 +1,106 @@
.btn {
padding: .5lh 1lh;
border: none;
border-radius: .5lh;
--btn-color: var(--fg-color);
/* color: var(--text-color); */
background-color: var(--btn-color);
font-weight: bold;
font-size: 1rem;
--transition-duration-short: 50ms;
--transition-duration-medium: 100ms;
--transition-duration-long: 200ms;
--transition-duration-bg-color: var(--transition-duration-medium);
--transition-duration-filter: var(--transition-duration-long);
--transition-duration-outline: var(--transition-duration-medium);
transition:
background-color ease-out var(--transition-duration-bg-color),
filter ease-out var(--transition-duration-filter),
outline ease-in var(--transition-duration-outline);
--drop-shadow-opacity: .5;
--drop-shadow-offset-y: 0;
--drop-shadow-blur: .25rem;
filter: var(--filter);
--filter:
brightness(var(--brightness, 1))
grayscale(var(--grayscale, 0));
cursor: pointer;
&:not(.flat) {
--drop-shadow: drop-shadow(
rgba(0, 0, 0, var(--drop-shadow-opacity))
0 var(--drop-shadow-offset-y) var(--drop-shadow-blur)
);
@supports (color: rgb(from black r g b / 0.5)) {
--drop-shadow: drop-shadow(
rgba(from var(--bg-color) r g b / var(--drop-shadow-opacity))
0 var(--drop-shadow-offset-y) var(--drop-shadow-blur)
);
}
filter: var(--filter) var(--drop-shadow);
}
&:not(:disabled):not(.flat):hover {
background-color: color-mix(in oklab, var(--btn-color) 80%, var(--bg-color));
--drop-shadow-opacity: .8;
--drop-shadow-offset-y: .25rem;
--drop-shadow-blur: .4rem;
}
&:where(:disabled) {
--brightness: .5;
--grayscale: .5;
}
&.suggested:not(.destructive) {
--btn-color: var(--accent-color);
}
&.destructive:not(.suggested) {
--btn-color: #861c1c;
}
&:focus-visible {
outline-offset: 2px;
}
&.icon {
--text-color: transparent;
background: var(--icon-url) no-repeat;
background-size: contain;
overflow: hidden;
width: var(--icon-size, 1rem);
height: var(--icon-size, 1rem);
}
&.flat {
border-radius: 0;
padding: 0;
--transition-duration-filter: var(--transition-duration-short);
&:not(:disabled) {
&:hover, &:focus-visible {
--brightness: 1.5;
}
&:active {
--brightness: 1.75;
}
}
}
/*
This class is just a hint, so this is on a best-effort basis.
If it works, it works, if not, then not.
*/
&.full-width {
width: -moz-available;
width: -webkit-fill-available;
}
}

View File

@@ -1,4 +1,4 @@
@import url("./main.css"); @import url("main.css");
@import url('https://fonts.googleapis.com/css2?family=Flow+Circular&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Flow+Circular&display=swap');
:root { :root {
@@ -226,44 +226,6 @@ a {
display: flex; display: flex;
} }
#delete-btn {
background: #861c1c;
}
/* button styling to be revisited */
.btn {
padding: .5lh 1lh;
border: none;
border-radius: .5lh;
--btn-color: var(--fg-color);
background-color: var(--btn-color);
color: var(--text-color);
font-weight: bold;
font-size: 1rem;
transition: background-color 100ms, filter 200ms;
transition-timing-function: ease-out;
--drop-shadow-opacity: .5;
--drop-shadow-offset-y: 0;
--drop-shadow-blur: .25rem;
--drop-shadow: drop-shadow(
rgba(0, 0, 0, var(--drop-shadow-opacity))
0 var(--drop-shadow-offset-y) var(--drop-shadow-blur)
);
filter: var(--drop-shadow);
}
.btn:focus-visible, #is-dataset:focus-visible + #is-dataset-toggle {
outline-offset: 2px;
}
.btn:not(:disabled):hover {
background-color: color-mix(in oklab, var(--btn-color) 80%, var(--bg-color));
--drop-shadow-opacity: .8;
--drop-shadow-offset-y: .25rem;
--drop-shadow-blur: .4rem;
}
#nothing-found-bg { #nothing-found-bg {
background-position-x: calc(50% + 3cqh); background-position-x: calc(50% + 3cqh);
} }

View File

@@ -13,9 +13,9 @@
<body> <body>
<template id="voting-template"> <template id="voting-template">
<aside class="upvote"> <aside class="upvote">
<button class="upvote-btn btn flat">Upvote</button> <button class="upvote-btn btn flat icon">Upvote</button>
<span class="upvote-count">0</span> <span class="upvote-count">0</span>
<button class="downvote-btn btn flat">Downvote</button> <button class="downvote-btn btn flat icon">Downvote</button>
</aside> </aside>
</template> </template>
@@ -29,9 +29,9 @@
</summary> </summary>
<a id="url">https://example.com/dataset</a> <a id="url">https://example.com/dataset</a>
<aside class="upvote"> <aside class="upvote">
<button disabled class="upvote-btn btn flat">Upvote</button> <button disabled class="upvote-btn btn flat icon">Upvote</button>
<span class="upvote-count">0</span> <span class="upvote-count">0</span>
<button disabled class="downvote-btn btn flat">Downvote</button> <button disabled class="downvote-btn btn flat icon">Downvote</button>
</aside> </aside>
</header> </header>
@@ -60,8 +60,8 @@
</p> </p>
</section> </section>
<section id="details-btns"> <section id="details-btns">
<button id="back-btn" class="btn">Back to main page</button> <button id="back-btn" class="btn suggested">Back to main page</button>
<button id="delete-btn" class="hidden btn">Delete</button> <button id="delete-btn" class="hidden btn destructive">Delete</button>
</section> </section>
</main> </main>

View File

@@ -18,25 +18,20 @@ const deleteButton = document.getElementById("delete-btn");
let dataset = null; let dataset = null;
let currentRating = 0; let currentRating = 0;
let isRated = false;
const currentLocation = new URL(location.href); const currentLocation = new URL(location.href);
if (currentLocation.searchParams.has("id")) { if (currentLocation.searchParams.has("id")) {
const id = currentLocation.searchParams.get("id"); const id = currentLocation.searchParams.get("id");
const response = await fetch(`${currentLocation.origin}/api/v1/datasets/id/${id}`); const response = await fetch(`/api/v1/datasets/id/${id}`);
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
dataset = new Dataset(data); dataset = new Dataset(data);
const upvoteComponent = dataset.createUpvoteComponent(); const upvoteComponent = dataset.createUpvoteComponent();
console.log(dataset.storageGet());
debugger
if (dataset.storageGetKey("created-locally", false)) { if (dataset.storageGetKey("created-locally", false)) {
deleteButton.classList.remove("hidden"); deleteButton.classList.remove("hidden");
} }
isRated = dataset.storageGetKey("is-rated", false)
title.innerText = dataset.title; title.innerText = dataset.title;
title.dataset.type = dataset.type.toLowerCase(); title.dataset.type = dataset.type.toLowerCase();
@@ -74,20 +69,21 @@ backButton.addEventListener("click", () => {
window.location.href = location.origin; window.location.href = location.origin;
}) })
deleteButton.addEventListener("click", () => { deleteButton.addEventListener("click", async () => {
if (dataset != null) { if (dataset != null) {
fetch(`${currentLocation.origin}/api/v1/datasets/id/` + dataset.id, { const response = await fetch(
method: 'DELETE' `/api/v1/datasets/id/${dataset.id}`,
}).then(resp => { { method: 'DELETE' }
if (resp.ok) { );
if (response.ok) {
window.location.href = location.origin; window.location.href = location.origin;
} }
});
} }
}); });
rating.addEventListener("mousemove", (event) => { rating.addEventListener("mousemove", (event) => {
if (!isRated) { if (!dataset.storageGetKey("is-rated", false)) {
let bounds = rating.getBoundingClientRect(); let bounds = rating.getBoundingClientRect();
currentRating = Math.round(((event.clientX - bounds.left) / bounds.width) * 5); currentRating = Math.round(((event.clientX - bounds.left) / bounds.width) * 5);
console.log(currentRating); console.log(currentRating);
@@ -100,22 +96,21 @@ rating.addEventListener("mouseleave", () => {
rating.value = dataset.rating; rating.value = dataset.rating;
}); });
rating.addEventListener("click", () => { rating.addEventListener("click", async () => {
if (!isRated) { if (!dataset.storageGetKey("is-rated", false)) {
fetch(`${currentLocation.origin}/api/v1/datasets/id/` + dataset.id + "/stars?stars=" + currentRating, { const starsResponse = await fetch(
method: 'PUT' `/api/v1/datasets/id/${dataset.id}/stars?stars=${currentRating}`,
}).then(resp => { { method: 'PUT' }
if (resp.ok) { );
if (starsResponse.ok) {
dataset.storageSetKey("is-rated", true); dataset.storageSetKey("is-rated", true);
isRated = true; const response = await fetch(`/api/v1/datasets/id/${dataset.id}`);
fetch(`${currentLocation.origin}/api/v1/datasets/id/` + dataset.id) const data = await response.json();
.then(resp => resp.json())
.then((data) => {
dataset = new Dataset(data); dataset = new Dataset(data);
ratingText.innerText = parseFloat(dataset.rating).toFixed(1); ratingText.innerText = parseFloat(dataset.rating).toFixed(1);
rating.value = dataset.rating; rating.value = dataset.rating;
});
} }
});
} }
}) })

View File

@@ -13,7 +13,7 @@
<script type="module" src="main.js" defer></script> <script type="module" src="main.js" defer></script>
</head> </head>
<body> <body>
<div id="add-btn" title="Add a new API entry"></div> <div id="add-btn" class="btn flat icon" title="Add a new API entry"></div>
<main> <main>
<header> <header>
<h1>Welcome to DataDash</h1> <h1>Welcome to DataDash</h1>
@@ -29,16 +29,16 @@
</div> </div>
</div> </div>
<aside class="upvote"> <aside class="upvote">
<button class="upvote-btn btn flat">Upvote</button> <button class="upvote-btn btn flat icon">Upvote</button>
<span class="upvote-count">0</span> <span class="upvote-count">0</span>
<button class="downvote-btn btn flat">Downvote</button> <button class="downvote-btn btn flat icon">Downvote</button>
</aside> </aside>
</li> </li>
</template> </template>
<section id="tool-bar"> <section id="tool-bar">
<button class="btn flat" id="reset-tools-btn" title="Reset search results">Reset</button> <button class="btn flat icon" id="reset-tools-btn" title="Reset search results">Reset</button>
<select id="sort-btn" class="btn flat" title="Sort entries">Sort by <select id="sort-btn" class="btn flat icon" title="Sort entries">Sort by
<option id="default-sort">Date newest-oldest</option> <option id="default-sort">Date newest-oldest</option>
<option>Date oldest-newest</option> <option>Date oldest-newest</option>
<option>Author A-Z</option> <option>Author A-Z</option>
@@ -51,7 +51,7 @@
<option>Upvotes ↓</option> <option>Upvotes ↓</option>
</select> </select>
<div class="divider"></div> <div class="divider"></div>
<select class="btn flat" id="filter-btn" title="Filter entries">Filter <select class="btn flat icon" id="filter-btn" title="Filter entries">Filter
<option id="default-filter">None</option> <option id="default-filter">None</option>
<optgroup label="Standard categories"> <optgroup label="Standard categories">
<option>Dataset</option> <option>Dataset</option>
@@ -61,7 +61,7 @@
</optgroup> </optgroup>
</select> </select>
<input type="search" name="query" id="search-entry" placeholder="Search"> <input type="search" name="query" id="search-entry" placeholder="Search">
<button class="btn flat" id="search-btn" title="Search entries">Search</button> <button class="btn flat icon" id="search-btn" title="Search entries">Search</button>
</section> </section>
<section id="recents"> <section id="recents">

View File

@@ -1,3 +1,5 @@
@import url("buttons.css");
:root { :root {
--bg-color: #222; --bg-color: #222;
--fg-color: #555; --fg-color: #555;
@@ -13,11 +15,17 @@
--corner-radius: 1rem; --corner-radius: 1rem;
font-size: 12pt; font-size: 12pt;
font-family: sans-serif; font-family: sans-serif;
scrollbar-gutter: stable both-edges;
scrollbar-color: var(--fg-color) var(--bg-color);
}
* {
color: var(--text-color, white);
} }
body { body {
background-color: var(--bg-color, black); background-color: var(--bg-color, black);
color: var(--text-color, white); /* color: var(--text-color, white); */
margin: 0; margin: 0;
} }
@@ -34,18 +42,22 @@ header {
} }
#add-btn { #add-btn {
width: 7rem; --icon-size: 7rem;
height: 7rem; --icon-url: linear-gradient(135deg, pink, darkblue);
content: url("add-button-mask.svg"); content: url("add-button-mask.svg");
background: linear-gradient(135deg, pink, darkblue);
clip-path: polygon(0% 0%, 100% 0%, 0% 100%); clip-path: polygon(0% 0%, 100% 0%, 0% 100%);
cursor: pointer;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
z-index: 1; z-index: 1;
&:hover, &:focus-visible {
--brightness: 1.2;
}
&:active {
--brightness: 1.3;
}
} }
#tool-bar { #tool-bar {
@@ -131,29 +143,13 @@ header {
} }
/* Buttons */ /* Buttons */
.upvote-btn, .downvote-btn, #search-btn, #filter-btn, #sort-btn, #reset-tools-btn { .downvote-btn, .upvote-btn {
background: var(--icon-url) no-repeat;
background-size: contain;
border: none;
width: var(--icon-size);
height: var(--icon-size);
padding: 0;
overflow: hidden;
color: transparent;
cursor: pointer;
}
.downvote-btn, .upvote-btn{
--icon-url: url(triangle.svg); --icon-url: url(triangle.svg);
--icon-size: 2rem; --icon-size: 2rem;
}
:is(.downvote-btn, .upvote-btn):disabled { &:disabled {
filter: brightness(1.75); --brightness: 1.75;
} }
:is(.downvote-btn, .upvote-btn).isVoted {
filter: brightness(1.1);
} }
.downvote-btn { .downvote-btn {
@@ -162,22 +158,18 @@ header {
#search-btn { #search-btn {
--icon-url: url(looking-glass.svg); --icon-url: url(looking-glass.svg);
--icon-size: 1rem;
} }
#filter-btn { #filter-btn {
--icon-url: url(filter.svg); --icon-url: url(filter.svg);
--icon-size: 1rem;
} }
#reset-tools-btn { #reset-tools-btn {
--icon-url: url(reset.svg); --icon-url: url(reset.svg);
--icon-size: 1rem;
} }
#sort-btn { #sort-btn {
--icon-url: url(sort.svg); --icon-url: url(sort.svg);
--icon-size: 1rem;
} }
.divider { .divider {
@@ -186,24 +178,8 @@ header {
background-color: var(--bg-color); background-color: var(--bg-color);
} }
#add-btn:is(:hover, :focus-visible) { :is(.upvote-btn, .downvote-btn).isVoted {
filter: brightness(1.2); --brightness: 1.1;
}
#add-btn:active {
filter: brightness(1.3);
}
.btn.flat {
transition: filter ease-out 50ms;
}
.btn.flat:is(:hover, :focus-visible):not(:disabled) {
filter: brightness(1.5);
}
.btn.flat:active:not(:disabled){
filter: brightness(1.75);
} }
select * { select * {