Skip to content

Commit fafe332

Browse files
committed
Add tag highlighting
1 parent 5e84926 commit fafe332

File tree

6 files changed

+65
-4
lines changed

6 files changed

+65
-4
lines changed

.hintrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": [
3+
"development"
4+
],
5+
"hints": {
6+
"no-inline-styles": "off"
7+
}
8+
}

src/common/components/IconButton/IconButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
1414
{...buttonProps}
1515
ref={ref}
1616
className={classNames(
17-
"size-8 rounded-full stroke-white text-white hover:bg-blue-500 active:bg-blue-600 place-content-center place-items-center flex outline-offset-2",
17+
"size-8 rounded-full stroke-white text-white hover:bg-blue-500 active:bg-blue-600 place-content-center place-items-center flex outline-offset-2 shadow-md shadow-blue-400",
1818
{
1919
"bg-blue-400": relevancy === "primary",
2020
"bg-stone-400": relevancy === "secondary",

src/container/SparkList/SparkList.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useLiveQuery } from "dexie-react-hooks";
22
import { sparkService } from "../../scripts/db/SparkService";
33
import { differenceInCalendarDays, format } from "date-fns";
44
import type Spark from "../../interfaces/Spark";
5+
import { stringToHue } from "../../scripts/utils/stringUtils";
56

67
type SparkSection = {
78
key: string;
@@ -100,11 +101,17 @@ export const SparkList = () => {
100101
className="grid grid-cols-[25%_1fr] gap-4 mb-6"
101102
>
102103
<div className="py-2 border-e border-slate-300 pe-4">
103-
<div className="sticky top-4 flex flex-col gap-1 text-end">
104+
<div className="sticky top-4 flex flex-col gap-1 items-end">
104105
{section.prefixTags.map((tag) => (
105106
<span
106107
key={tag}
107-
className="font-semibold text-neutral-400 text-sm"
108+
className="font-semibold text-neutral-400 tag w-fit"
109+
style={
110+
{
111+
"--tag-color":
112+
stringToHue(tag),
113+
} as React.CSSProperties
114+
}
108115
>
109116
{tag}
110117
</span>

src/scripts/utils/stringUtils.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { extractTags } from "./stringUtils";
1+
import { extractTags, stringToHue } from "./stringUtils";
22

33
describe("extractTags", () => {
44
test("returns the correct prefixTags and remainingTags", () => {
@@ -57,3 +57,13 @@ describe("extractTags", () => {
5757
expect(strippedContent).toEqual(expectStrippedContent);
5858
});
5959
});
60+
61+
describe("stringToHue", () => {
62+
test("Returns a deterministic value", () => {
63+
const input = "Heart to heart";
64+
65+
const hue = stringToHue(input);
66+
67+
expect(hue).toBe(122);
68+
});
69+
});

src/scripts/utils/stringUtils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,19 @@ export const extractTags = (content: string): [string[], string[], string] => {
2424

2525
return [prefixTags, remainingTags, strippedContent];
2626
};
27+
28+
/**
29+
* Returns a deterministic number between 0-360 for a given string.
30+
*
31+
* @param str The input string
32+
* @returns a number between 0 and 360
33+
*/
34+
export const stringToHue = (str: string) => {
35+
let numberHash = 0;
36+
37+
for (let i = 0; i < str.length; i++) {
38+
numberHash += (i + 1) * str.charCodeAt(i);
39+
}
40+
41+
return numberHash % 360;
42+
};

src/styles/global.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,23 @@ html {
7070
@apply bg-background text-foreground;
7171
}
7272
}
73+
74+
75+
.tag::after {
76+
/*
77+
We use hsl to generate the base color because the hue in hsl has a wider color range than oklch.
78+
See https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
79+
But oklch allows for a consistent lightness perceived by humans.
80+
See https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl
81+
That's why wrap the hsl value in oklch, creating a relative value with constant
82+
lightness, chroma and alpha but keep the hue
83+
*/
84+
background: oklch(from hsl(var(--tag-color) 100% 50%) 0.5 0.5 h / 0.4);
85+
/* background: linear-gradient(0deg, rgba(255,255,255,0) 0%, oklch(from hsl(var(--tag-color) 100% 50%) 0.5 0.5 h) 80%, rgba(255,255,255,0) 100%); */
86+
width: 100%;
87+
height: 2px;
88+
filter: blur(3px);
89+
margin-top: -5px;
90+
display: block;
91+
content: "";
92+
}

0 commit comments

Comments
 (0)