feat: add filter list component

This commit is contained in:
Sebin Nyshkim 2025-05-02 16:50:24 +02:00
parent aa410f916a
commit 9d9e00c560
3 changed files with 287 additions and 48 deletions

View file

@ -0,0 +1,230 @@
<script webc:setup>
const ratings = ['No', 'Maybe', 'Yes', 'Love'];
const getRating = (rating) => ratings[rating];
const getSorted = (collection) => collection.sort((a, b) => b.rating - a.rating);
</script>
<div webc:root="override">
<div class="buttons">
<div class="filter-button" webc:for="rating of ratings">
<input type="checkbox" :name="rating" :id="`button-${rating.toLowerCase()}`" />
<label :for="`button-${rating.toLowerCase()}`" @text="rating"></label>
</div>
</div>
<ul class="list">
<li webc:for="row of getSorted(data)" class="item" :class="getRating(row.rating).toLowerCase()">
<span class="tag rating" :class="getRating(row.rating).toLowerCase()">
<span @text="getRating(row.rating)"></span>
</span>
<span class="name" @text="row.name"></span
><span class="tag receive" webc:if="row.receive"><span>Receive</span></span
><span class="tag give" webc:if="row.give"><span>Give</span></span>
</li>
</ul>
<p class="intro">Select one of the categories above</p>
</div>
<style webc:scoped="filter-list">
:host {
--clr-love: oklch(60% 0.25 10deg);
--clr-yes: oklch(65% 0.2 140deg);
--clr-maybe: oklch(75% 0.15 85deg);
--clr-no: oklch(40% 0.15 30deg);
--clr-tag: oklch(65% 0.15 245deg);
}
:host {
position: relative;
background: linear-gradient(
to bottom right,
var(--clr-box-gradient-start) 0%,
var(--clr-box-gradient-end) 50%
);
font-size: 0.75em;
box-shadow: 0.125em 0.125em 0.5em var(--clr-box-shadow);
margin-block: 1em;
border-radius: 1em;
padding-block: 0 1em;
z-index: 1;
@media (min-width: 40em) {
font-size: 1em;
}
}
:host::before {
content: '';
position: absolute;
inset: var(--border-thin);
background: linear-gradient(
to bottom right,
var(--clr-quick-info-bg-start) 0%,
var(--clr-quick-info-bg-end) 50%
);
border-radius: inherit;
z-index: -1;
}
:host .buttons {
display: flex;
flex-flow: row-reverse nowrap;
gap: 0.75em;
padding: 0.5em 0.75em;
}
:host .filter-button {
flex: 1 1 0;
}
:host .filter-button input {
display: none;
}
:host .filter-button input:checked + label {
--box-shadow-size: 0.25em;
--button-top: 0.25em;
}
:host .filter-button label {
display: block;
position: relative;
top: var(--button-top, 0);
background-color: var(--clr-button);
font-weight: 700;
text-decoration: none;
text-align: center;
color: var(--theme-c-primary-100);
margin: 0.5em 0;
border-radius: 0.25em;
padding: 0.5em 1em;
box-shadow: 0 var(--box-shadow-size, 0.5em) 0 0 oklch(from var(--clr-button) calc(l - 0.3) c h);
transition: all 0.1s ease-out;
}
:host .filter-button label:hover {
--box-shadow-size: 0.75em;
--button-top: -0.25em;
cursor: pointer;
}
:host .filter-button label[for='button-love'] {
--clr-button: var(--clr-love);
}
:host .filter-button label[for='button-yes'] {
--clr-button: var(--clr-yes);
}
:host .filter-button label[for='button-maybe'] {
--clr-button: var(--clr-maybe);
}
:host .filter-button label[for='button-no'] {
--clr-button: var(--clr-no);
}
:host .list {
list-style: none;
max-height: 30em;
margin: 0;
padding: 0;
overflow: scroll;
}
:host .item {
display: none;
}
:host .item:hover {
background-color: rgb(0 0 0 / 0.3);
}
:host:has(#button-love:checked) .item.love,
:host:has(#button-yes:checked) .item.yes,
:host:has(#button-maybe:checked) .item.maybe,
:host:has(#button-no:checked) .item.no {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
gap: 0.5em;
padding-block: 0.25em;
padding-inline: 0.875em;
}
:host .intro {
font-size: 2em;
font-weight: bold;
font-style: italic;
text-align: center;
hyphens: none;
}
:host:has(input:checked) .intro {
display: none;
}
:host .item .rating {
flex: 0 0 5em;
}
:host .item .name {
flex: 1 0 0;
}
:host .item .tag {
display: block;
font-size: 0.75em;
font-weight: bold;
text-align: center;
color: var(--theme-c-primary-100);
background: var(--tag-bg);
border: 0.125em solid oklch(from var(--tag-bg) calc(l - 0.1) c h);
border-radius: 1em;
padding: 0 0.5em;
}
:host .item .rating.love {
--tag-bg: var(--clr-love);
}
:host .item .rating.yes {
--tag-bg: var(--clr-yes);
}
:host .item .rating.maybe {
--tag-bg: var(--clr-maybe);
}
:host .item .rating.no {
--tag-bg: var(--clr-no);
}
:host .item .tag.receive {
--tag-bg: var(--clr-tag);
}
:host .item .tag.give {
--tag-bg: oklch(from var(--clr-tag) calc(l - 0.1) calc(c - 0.1) h);
}
</style>

View file

@ -25,3 +25,11 @@ Sebin's day starts with a strong cup of black coffee and sandwiches. He's also a
Besides snacking, Sebin also likes to eat hearty and savory things. He doesn't disdain a cheese platter with a wide selection, nor a medium-rare steak.
Sebin rarely says no to a good beer with friends, just as he rarely says no to a bar tour to try new and interesting cocktails.
## test
<nsfw-barrier></nsfw-barrier>
## Kinks
<filter-list :@data="$data.kinks"></filter-list>

View file

@ -108,55 +108,55 @@ const firstName = 'Sebin',
description:
'A rather defensive technique. By spinning around with stretched out arms Sebin creates fire balls, which he usually hurls towards enemies, that circle around his body diagonally. They act as a shield while he can still move his arms relatively freely. Enemies would be well advised to keep their distance to this spinning shield, as the fire balls will still explode on contact.'
}
],
kinks = [
{ name: 'Absorption', rating: 0 },
{ name: 'Anal', rating: 3, receive: true, give: true },
{ name: 'Auto-Fellatio', rating: 2 },
{ name: 'Biting', rating: 2, receive: true, give: true },
{ name: 'Bukkake', rating: 2, give: true },
{ name: 'Chastity', rating: 0 },
{ name: 'Chubby', rating: 1 },
{ name: 'Clothed Sex', rating: 2 },
{ name: 'Cock Slapping', rating: 2, give: true },
{ name: 'Coiling', rating: 1, give: true },
{ name: 'Competition', rating: 1, give: true },
{ name: 'Creampie', rating: 2, give: true },
{ name: 'Crushing (Living/Objects)', rating: 0 },
{ name: 'Cum From Mouth/Nose', rating: 2, give: true },
{ name: 'Cum Inflation (Light/Medium)', rating: 2 },
{ name: 'Deep-throat', rating: 2, receive: true },
{ name: 'Dirty Talking', rating: 2 },
{ name: 'Excessive Cum', rating: 3, receive: true, give: true },
{ name: 'Face-Fucking', rating: 2, give: true },
{ name: 'Facial', rating: 2, give: true },
{ name: 'Feet', rating: 0 },
{ name: 'Filled Condoms', rating: 2 },
{ name: 'Foreplay', rating: 2, receive: true, give: true },
{ name: 'Frotting', rating: 2 },
{ name: 'Gangbangs', rating: 2 },
{ name: 'Growth', rating: 3, receive: true },
{ name: 'Handjobs', rating: 2, receive: true, give: true },
{ name: 'Hotdogging', rating: 2, give: true },
{ name: 'Kissing', rating: 2, receive: true, give: true },
{ name: 'Macro', rating: 3 },
{ name: 'Milking', rating: 2 },
{ name: 'Muscle Growth', rating: 3, receive: true, give: true },
{ name: 'Muscle Worship', rating: 2, receive: true, give: true },
{ name: 'Nipple Play', rating: 2, receive: true, give: true },
{ name: 'Oral', rating: 3, receive: true, give: true },
{ name: 'Rough', rating: 2, receive: true, give: true },
{ name: 'Sheath Play', rating: 2, receive: true, give: true },
{ name: 'Size Difference', rating: 3 },
{ name: 'Slime/Goo Characters', rating: 2 },
{ name: 'Spanking', rating: 1, give: true },
{ name: 'Tailsex', rating: 2, receive: true, give: true },
{ name: 'Toys', rating: 2, receive: true, give: true },
{ name: 'Underwear', rating: 3 },
{ name: 'Unsanitary', rating: 0 },
{ name: 'Verbal Abuse', rating: 1, give: true },
{ name: 'Vore', rating: 0 }
];
// kinks = [
// { name: 'Absorption', rating: Ratings.No },
// { name: 'Anal', rating: Ratings.Love, role: Role.Both },
// { name: 'Auto-Fellatio', rating: Ratings.Yes },
// { name: 'Biting', rating: Ratings.Yes, role: Role.Both },
// { name: 'Bukkake', rating: Ratings.Yes, role: Role.Give },
// { name: 'Chastity', rating: Ratings.No },
// { name: 'Chubby', rating: Ratings.Maybe },
// { name: 'Clothed Sex', rating: Ratings.Yes },
// { name: 'Cock Slapping', rating: Ratings.Yes, role: Role.Give },
// { name: 'Coiling', rating: Ratings.Maybe, role: Role.Give },
// { name: 'Competition', rating: Ratings.Maybe, role: Role.Give },
// { name: 'Creampie', rating: Ratings.Yes, role: Role.Give },
// { name: 'Crushing (Living/Objects)', rating: Ratings.No },
// { name: 'Cum From Mouth/Nose', rating: Ratings.Yes, role: Role.Give },
// { name: 'Cum Inflation (Light/Medium)', rating: Ratings.Yes },
// { name: 'Deep-throat', rating: Ratings.Yes, role: Role.Receive },
// { name: 'Dirty Talking', rating: Ratings.Yes },
// { name: 'Excessive Cum', rating: Ratings.Love, role: Role.Both },
// { name: 'Face-Fucking', rating: Ratings.Yes, role: Role.Give },
// { name: 'Facial', rating: Ratings.Yes, role: Role.Give },
// { name: 'Feet', rating: Ratings.No },
// { name: 'Filled Condoms', rating: Ratings.Yes },
// { name: 'Foreplay', rating: Ratings.Yes, role: Role.Both },
// { name: 'Frotting', rating: Ratings.Yes },
// { name: 'Gangbangs', rating: Ratings.Yes },
// { name: 'Growth', rating: Ratings.Love, role: Role.Receive },
// { name: 'Handjobs', rating: Ratings.Yes, role: Role.Both },
// { name: 'Hotdogging', rating: Ratings.Yes, role: Role.Give },
// { name: 'Kissing', rating: Ratings.Yes, role: Role.Both },
// { name: 'Macro', rating: Ratings.Love },
// { name: 'Milking', rating: Ratings.Yes },
// { name: 'Muscle Growth', rating: Ratings.Love, role: Role.Both },
// { name: 'Muscle Worship', rating: Ratings.Yes, role: Role.Both },
// { name: 'Nipple Play', rating: Ratings.Yes, role: Role.Both },
// { name: 'Oral', rating: Ratings.Love, role: Role.Both },
// { name: 'Rough', rating: Ratings.Yes, role: Role.Both },
// { name: 'Sheath Play', rating: Ratings.Yes, role: Role.Both },
// { name: 'Size Difference', rating: Ratings.Love },
// { name: 'Slime/Goo Characters', rating: Ratings.Yes },
// { name: 'Spanking', rating: Ratings.Maybe, role: Role.Give },
// { name: 'Tailsex', rating: Ratings.Yes, role: Role.Both },
// { name: 'Toys', rating: Ratings.Yes, role: Role.Both },
// { name: 'Underwear', rating: Ratings.Love },
// { name: 'Unsanitary', rating: Ratings.No },
// { name: 'Verbal Abuse', rating: Ratings.Maybe, role: Role.Give },
// { name: 'Vore', rating: Ratings.No }
// ],
const getClientLocale = () => {
return navigator.languages.length > 0 ? navigator.languages[0] : 'en-US';
@ -289,6 +289,7 @@ export default {
pronouns,
orientation,
position,
kinks,
description,
attacks,
overdriveAttacks,