Skip to content

Commit

Permalink
0.7.0: Tweaks, Precens and Fixes (#9)
Browse files Browse the repository at this point in the history
- flag: scalability and minor design improvements
- tlcc: design improvements
- rewind: scalability and design improvements for smol screens
- fix screenshots on mobile (smol screens)
- kinks: remove Children (reasoning in commit 64462cd)

technical:
- adjust kinkcheck internal representation and serialization according to procens plans (and update tests accordingly)
- use culling in the `Input` and `Kink` components
- move unfinished and internal pages to their own directory
- deploy: use npm clean-install
- minor dependency upgrades
  • Loading branch information
pixelcmtd authored Jul 16, 2024
1 parent 72c0b43 commit aa96d7b
Show file tree
Hide file tree
Showing 27 changed files with 1,427 additions and 1,832 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.DS_Store
.env
10 changes: 9 additions & 1 deletion .stylelintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
{
"extends": "stylelint-config-standard"
"extends": "stylelint-config-standard",
"rules": {
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["global"]
}
]
}
}
2 changes: 1 addition & 1 deletion deploy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/sh
set -uxe

npm install
npm ci
npm run build
2,921 changes: 1,228 additions & 1,693 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "kinkcheck",
"type": "module",
"version": "0.6.0",
"version": "0.7.0",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
Expand All @@ -11,14 +11,14 @@
"test": "vitest"
},
"dependencies": {
"@astrojs/preact": "^3.0.0",
"astro": "^4.0.2",
"autoprefixer": "^10.4.16",
"cmdesigns": "^0.1.1",
"cssnano": "^6.0.1",
"@astrojs/preact": "^3.5.0",
"astro": "^4.11.3",
"autoprefixer": "^10.4.19",
"cmdesigns": "^0.1.2",
"cssnano": "^7.0.3",
"html2canvas": "^1.4.1",
"preact": "^10.17.1",
"preact": "^10.22.0",
"stylelint-config-standard": "^34.0.0",
"vitest": "^1.0.0"
"vitest": "^1.6.0"
}
}
72 changes: 31 additions & 41 deletions src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ export const ratings: [string, string][] = [

export type positions = [string, string] | [""];
export type kink = [string, positions, number] | [string, positions, number, string];
export type kinklist = { [k: string]: kink[] };
export type metadata = { kinks: kinklist, version: string };
export type kinklist = [string, kink[]][];
export type template_revision = { kinks: kinklist };

export const kinks: kinklist = {
"General": [
export const kinks: kinklist = [
["General", [
["Fellatio/Blowjobs", ["receive", "give"], 0],
["Cunnilingus", ["receive", "give"], 1, "giver licks receiver's vagina"],
["Face-Fucking", ["give", "receive"], 2],
["Face-Sitting", ["top", "bottom"], 3, "top sits on bottom's face"],
["Handjobs", ["give", "receive"], 4],
["Vaginal Penetration", ["top", "bottom"], 98],
["Vaginal Penetration", ["top", "bottom"], 97],
["Vaginal Fingering", ["give", "receive"], 5],
["Vaginal Fisting", ["give", "receive"], 6],
["Rough Sex", [""], 7],
Expand All @@ -32,8 +32,8 @@ export const kinks: kinklist = {
["Anal Fisting", ["top", "bottom"], 14],
["Pegging", ["top", "bottom"], 15, "top anally penetrates bottom with a strap-on"],
["Anilingus/Rimming", ["receive", "give"], 16, "bottom licks top's asshole"],
],
"BDSM": [
]],
["BDSM", [
["Little/Daddy*Mommy", ["dom", "sub"], 17],
["Slave/Master*Mistress", ["dom", "sub"], 18],
["Pet/Owner", ["dom", "sub"], 19],
Expand All @@ -60,8 +60,8 @@ export const kinks: kinklist = {
["Teasing", ["dom", "sub"], 42],
["Sounding/Urethral Insertion", ["dom", "sub"], 43],
["Worship", ["dom", "sub"], 44],
],
"Kinks": [
]],
["Kinks", [
["Incest", ["cousins", "siblings"], 45],
["Incest (any age)", ["parents", "children"], 46],
["Impregnation/Pregnancy", ["top", "bottom"], 47],
Expand All @@ -83,8 +83,8 @@ export const kinks: kinklist = {
["Titfuck", ["top", "bottom"], 62],
["Footjob", ["give", "receive"], 63],
["Armpit Sex", ["top", "bottom"], 64],
],
"Pain": [
]],
["Pain", [
["Physical Pain", ["give", "receive"], 65],
["Nipple Clamps", ["give", "receive"], 66],
["Hard Spanking", ["give", "receive"], 67],
Expand All @@ -97,8 +97,8 @@ export const kinks: kinklist = {
["Vagina Slapping", ["give", "receive"], 74],
["Clothespins", ["give", "receive"], 75],
["Needles", ["give", "receive"], 76],
],
"Clothing": [
]],
["Clothing", [
["Clothed Sex", [""], 77],
["Collars", ["dom", "sub"], 78, "sub wears a collar, which might have a leash for dom to pull on"],
["Latex", [""], 79],
Expand All @@ -111,33 +111,28 @@ export const kinks: kinklist = {
["Uniforms", [""], 86],
["Cosplay", [""], 87],
["Furry", [""], 88],
],
"Extreme": [
]],
["Extreme", [
["Scat", [""], 89],
["Cutting", ["give", "receive"], 90],
["Raceplay", ["dom", "sub"], 91],
["Bestiality", [""], 92],
["Necrophilia", [""], 93],
["Hard Rape", ["top", "bottom"], 94],
["Children", [""], 95],
["Blood", [""], 96],
["Cannibalism", ["dom", "sub"], 97],
["Cannibalism", ["dom", "sub"], 95],
["Torture", ["dom", "sub"], 20],
["Genital Mutilation", ["give", "receive"], 21],
],
};
]],
];

const valueForAllKinks = <T>(kinks: kinklist, x: T) => Object.fromEntries(
Object.entries(kinks).map<[string, T[][]]>(
([cat, kinks]) => [cat, kinks.map((k) => k[1].map(() => x))])
);
const valueForAllKinks = <T>(kinks: kinklist, x: T) =>
kinks.map<T[][]>((c) => c[1].map((k) => k[1].map(() => x)));

export type ratings = { [k: string]: number[][] };
export type ratings = number[][][];
export const defaultRatings = (kinks: kinklist): ratings => valueForAllKinks(kinks, 0);
export type checklist = { [k: string]: boolean[][] };
export const defaultChecklist = (kinks: kinklist): checklist => valueForAllKinks(kinks, false);
export type kinkcheck = { ratings: ratings };
export const defaultKinkcheck = (kinks: kinklist): kinkcheck => { return { ratings: defaultRatings(kinks) } };
export const defaultKinkcheck = (kinks: kinklist): kinkcheck => ({ ratings: defaultRatings(kinks) });

function packIndexedValues<T>(indexedValues: [number, T][]): T[] {
return indexedValues.reduce<T[]>((arr, [idx, val]) => {
Expand All @@ -146,24 +141,19 @@ function packIndexedValues<T>(indexedValues: [number, T][]): T[] {
}, Array(Math.max(...indexedValues.map(([idx]) => idx))));
}

export function encodeKinkCheck({ kinks, version }: metadata, { ratings }: kinkcheck): string {
const p = packIndexedValues(
Object.entries(kinks).flatMap(([, kinks]) => kinks
.map<[number, boolean]>(([, pos, id]) => [id, pos.length === 2])));
const r = packIndexedValues(Object.entries(ratings)
.flatMap(([cat, rats]) => kinks[cat].map<[number, number[]]>(([, , id], i) => [id, rats[i]])));
return JSON.stringify({ version, ratings: r });
export function encodeKinkCheck({ kinks }: { kinks: kinklist }, { ratings }: kinkcheck): string {
const r = packIndexedValues(ratings.flatMap((_, cat) =>
kinks[cat][1].map<[number, number[]]>(([, , id], i) => [id, ratings[cat][i]])));
return JSON.stringify({ ratings: r });
}

export function decodeKinkCheck({ kinks, version }: metadata, s: string): kinkcheck {
const x = JSON.parse(s);
if (x.version !== version)
throw "unsupported kinkcheck serialization version";
export function decodeKinkCheck({ kinks }: { kinks: kinklist }, s: string): kinkcheck {
const ratings = defaultRatings(kinks);
x.ratings.forEach((rat: number[], id: number) => {
Object.keys(ratings).forEach((cat) => {
JSON.parse(s).ratings.forEach((rat: number[] | undefined, id: number) => {
if (!rat) return;
ratings.forEach((_, cat) => {
ratings[cat].forEach((_, i) => {
if (kinks[cat][i][2] === id) {
if (kinks[cat][1][i][2] === id) {
ratings[cat][i] = rat;
}
});
Expand Down
9 changes: 5 additions & 4 deletions src/components/FlagGenerator.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
.input {
margin-top: 8px;
margin-bottom: 8px;
font-size: 16pt;
margin: 0.5em 0;
border: 0;
padding: 0.25em;
font-size: 2em;
width: 14.5em;
background-color: rgb(var(--cmblack));
color: white;
border: 0;
}
10 changes: 5 additions & 5 deletions src/components/FlagGenerator.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "preact/hooks";
import styles from "./FlagGenerator.module.css";

const colors = {
const colors: { [k: string]: string } = {
"t": "rgb(var(--transblue))",
"r": "rgb(var(--transpink))",
"a": "white",
Expand All @@ -13,16 +13,16 @@ export default function FlagGenerator() {
const [flag, setFlag] = useState("");
let input: HTMLInputElement;
const chars = [...flag.toLowerCase()].filter(x => "trans".includes(x));
const height = 400 / chars.length;
const height = 20 / chars.length;
useEffect(() => input.focus());
return (
<main>
<input ref={x => input = x!} type="text" placeholder="trans, rat, ant, ..."
spellcheck={false} autocorrect="off" class={styles.input}
value={flag} onInput={e => setFlag(e.target.value)} />
value={flag} onInput={e => setFlag(e.target!.value)} />
{chars.length ? chars.map(x => (
<div style={{ width: 600, backgroundColor: colors[x], height }} />
)) : <div style={{ width: 600, backgroundColor: "transparent", height: 400 }} />}
<div style={{ width: "30em", backgroundColor: colors[x], height: `${height}em` }} />
)) : <div style={{ width: "30em", backgroundColor: "transparent", height: "20em" }} />}
</main>
);
}
6 changes: 3 additions & 3 deletions src/components/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type StateUpdater } from "preact/hooks";
import { type Dispatch, type StateUpdater } from "preact/hooks";

export default function Input({ error, placeholder, value, setValue, className }:
{ error?: string, placeholder: string, value: string, setValue: StateUpdater<string>, className?: string }) {
{ error?: string, placeholder: string, value: string, setValue: Dispatch<StateUpdater<string>>, className?: string }) {
return <div className={className}>
<input type="text" spellcheck={false} autocorrect="false"
placeholder={placeholder} value={value} onInput={(e) => setValue(e.target.value)} />
<span style={{ color: "red" }}>{error}</span>
{error && <span style={{ color: "red" }}>{error}</span>}
</div>;
}
2 changes: 1 addition & 1 deletion src/components/Kink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function Kink({ kink: [kink, positions, , description], ratings,
<tr class={styles.tr}>
<td class={styles.td}>
<span>{kink}</span>
<span class={styles.desc}>{description}</span>
{description && <span class={styles.desc}>{description}</span>}
</td>
{positions.map((pos, p) => (
<td class={styles.td}>
Expand Down
4 changes: 2 additions & 2 deletions src/components/KinkCheck.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
}

@media screen and (width <= 800px) {
.category,
.table {
:global(body:not(.screenshot)) .category,
:global(body:not(.screenshot)) .table {
width: 100%;
}
}
17 changes: 7 additions & 10 deletions src/components/KinkCheck.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from "preact/hooks";
import { defaultRatings, encodeKinkCheck, type kink, type metadata } from "../base";
import { defaultRatings, encodeKinkCheck, type kink, type template_revision } from "../base";
import Kink from "./Kink";
import styles from "./KinkCheck.module.css";

Expand Down Expand Up @@ -39,22 +39,19 @@ export function Category({ cat, kinks, ratings, setRating }: {
);
}

export default function KinkCheck(meta: metadata) {
export default function KinkCheck(meta: template_revision) {
const [ratings, setRatings] = useState(defaultRatings(meta.kinks));
const setRating = (cat: string) => (kink: number) => (pos: number) => (rat: number) => {
const c = ratings[cat];
const p = c[kink];
p[pos] = rat;
c[kink] = p;
const r = { ...ratings, [cat]: c };
const setRating = (cat: number) => (kink: number) => (pos: number) => (rat: number) => {
const r = [...ratings!];
r[cat][kink][pos] = rat;
setRatings(r);
console.log(encodeKinkCheck(meta, { ratings: r }));
};
// TODO: add a name field
return <main class={styles.catcontainer}>
{
Object.entries(meta.kinks).map(([cat, kinks]) => (
<Category cat={cat} kinks={kinks} ratings={ratings[cat]} setRating={setRating(cat)} />
meta.kinks.map(([cat, kinks], i) => (
<Category cat={cat} kinks={kinks} ratings={ratings[i]} setRating={setRating(i)} />
))
}
</main>;
Expand Down
16 changes: 7 additions & 9 deletions src/components/Matcher.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from "preact/hooks";
import { decodeKinkCheck, defaultKinkcheck, kinks, ratings, type metadata } from "../base";
import { decodeKinkCheck, defaultKinkcheck, kinks, ratings, type template_revision } from "../base";
import { Category } from "./KinkCheck";
import kc from "./KinkCheck.module.css";
import styles from "./Matcher.module.css";
Expand All @@ -11,21 +11,19 @@ function matchRating(a: number, b: number): number {
}

export function match(a: ratings, b: ratings): ratings {
if (!Object.keys(a).every((k) => Object.keys(b).includes(k))) throw "incompatible ratings";
return Object.fromEntries(Object.entries(a).map(
([cat, rA]) => [cat, rA.map((rsA, kink) => rsA.map((ratA, pos) => matchRating(ratA, b[cat][kink][pos])))]
));
// if (!Object.keys(a).every((k) => Object.keys(b).includes(k))) throw "incompatible ratings";
return a.map((rA, cat) => rA.map((rsA, kink) => rsA.map((ratA, pos) => matchRating(ratA, b[cat][kink][pos]))));
}

export default function Matcher(meta: metadata) {
export default function Matcher(meta: template_revision) {
const [partnerA, setPartnerA] = useState("");
const [partnerB, setPartnerB] = useState("");
let kcA = defaultKinkcheck(kinks);
let kcB = defaultKinkcheck(kinks);
let errorA, errorB;
try { kcA = decodeKinkCheck(meta, partnerA.trim()); } catch(e: any) { errorA = e.toString(); }
try { kcB = decodeKinkCheck(meta, partnerB.trim()); } catch(e: any) { errorB = e.toString(); }
kcB.ratings = Object.fromEntries(Object.entries(kcB.ratings).map(([k, r]) => [k, r.map(rs => rs.toReversed())]));
kcB.ratings = kcB.ratings.map(ks => ks.map(rs => rs.toReversed()));
const matched = match(kcA.ratings, kcB.ratings);
return <main>
<div class={styles.matcherfrontmatter + " " + kc.catcontainer}>
Expand All @@ -35,8 +33,8 @@ export default function Matcher(meta: metadata) {
</div>
<div class={kc.catcontainer}>
{
Object.entries(kinks).map(([cat, kinks]) => (
<Category cat={cat} kinks={kinks} ratings={matched[cat]} />
kinks.map(([cat, kinks], i) => (
<Category cat={cat} kinks={kinks} ratings={matched[i]} />
))
}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/RatingOverview.astro
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Rater from "./Rater";
font-size: 16pt;
}
@media screen and (width <= 800px) {
div {
:global(body:not(.screenshot)) div {
justify-content: space-between;
}
}
Expand Down
Loading

0 comments on commit aa96d7b

Please sign in to comment.