Browse Source

feat: separate Tooltip from FlickerList and finetune

master
Muthu Kumar 2 weeks ago
parent
commit
8c0f997a9b
Failed to extract signature
  1. 117
      src/components/FlickerList.tsx

117
src/components/FlickerList.tsx

@ -1,4 +1,4 @@
import React from "react"; import React, { forwardRef } from "react";
import { css, cx } from "@emotion/css"; import { css, cx } from "@emotion/css";
import { intersperse, sleep } from "../util"; import { intersperse, sleep } from "../util";
@ -39,6 +39,9 @@ const opaque = css`&& { opacity: 1 }`;
const halfVisible = css`&&& {opacity: 0.5}`; const halfVisible = css`&&& {opacity: 0.5}`;
// prettier-ignore // prettier-ignore
const invisible = css`& { opacity: 0 }`;
// prettier-ignore
const opacities = [0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45].map(each => css`&&& { opacity: ${0.5 + each} }`); const opacities = [0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45].map(each => css`&&& { opacity: ${0.5 + each} }`);
const tripleBlink = async (el: HTMLElement) => { const tripleBlink = async (el: HTMLElement) => {
@ -58,12 +61,14 @@ const tripleBlink = async (el: HTMLElement) => {
el.classList.remove(halfVisible); el.classList.remove(halfVisible);
}; };
const Flicker: React.FC<{ export const Tooltip = forwardRef<
children: React.ReactNode; HTMLButtonElement,
index: number; {
description: string; children: React.ReactNode;
style?: React.CSSProperties; description: React.ReactNode;
}> = ({ children, index, description, style }) => { style?: React.CSSProperties;
}
>(({ children, description, style }, ref) => {
return ( return (
<span <span
style={style} style={style}
@ -71,45 +76,27 @@ const Flicker: React.FC<{
position: relative; position: relative;
&&& button:focus ~ .tooltip, &&& button:focus ~ .tooltip,
&&& button:hover ~ .tooltip { &&&:hover .tooltip {
opacity: 1; opacity: 1;
pointer-events: all;
} }
&&& button:focus, &&& button:focus,
&&& button:hover { &&&:hover button {
opacity: 1; opacity: 1;
} }
`}> `}>
<button <button
className={css` className={css`
border-bottom: 1px dashed var(--text-colour); border-bottom: 1px dashed var(--text-colour);
opacity: 0;
background-color: transparent; background-color: transparent;
border: none; border: none;
color: inherit; color: inherit;
position: relative; position: relative;
font-size: 0.9rem; font-size: inherit;
padding: 0;
`} `}
ref={async el => { ref={ref}>
if (!el) return;
await sleep(500);
await sleep(300 * index);
el.classList.add(opaque);
await sleep(1000 + Math.random() * 1000);
tripleBlink(el);
while (true) {
await sleep(5000 + Math.random() * 10000);
const chosen =
opacities[Math.floor(Math.random() * opacities.length)];
el.classList.add(chosen);
await sleep(2000);
el.classList.remove(chosen);
tripleBlink(el);
}
}}>
{children} {children}
</button> </button>
<span <span
@ -118,22 +105,14 @@ const Flicker: React.FC<{
css` css`
/* tooltip */ /* tooltip */
position: absolute; position: absolute;
top: 150%; top: 100%;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
background: var(--card-tags);
color: var(--text-colour);
border-radius: 0.5rem;
padding: 0.5rem 0.8rem;
font-size: 0.8rem;
min-width: 20rem;
width: fit-content;
max-width: 80vw;
opacity: 0; opacity: 0;
transition: opacity 0.2s; transition: opacity 0.2s;
user-select: none; user-select: none;
text-align: left;
pointer-events: none; pointer-events: none;
z-index: 999;
@media screen and (max-width: 65rem) { @media screen and (max-width: 65rem) {
position: fixed; position: fixed;
@ -143,14 +122,31 @@ const Flicker: React.FC<{
} }
`, `,
)}> )}>
{description} <span
className={css`
margin: 0.5rem;
display: block;
min-width: 20rem;
width: fit-content;
max-width: 80vw;
background: var(--card-tags);
color: var(--text-colour);
border-radius: 0.5rem;
padding: 0.5rem 0.8rem;
font-size: 0.8rem;
text-align: left;
line-height: 1.4;
`}>
{description}
</span>
</span> </span>
</span> </span>
); );
}; });
const FlickerList: React.FC<{ const FlickerList: React.FC<{
list: { text: string; description: string }[]; list: { text: string; description: React.ReactNode }[];
style?: React.CSSProperties; style?: React.CSSProperties;
}> = ({ list, style }) => { }> = ({ list, style }) => {
return ( return (
@ -159,13 +155,13 @@ const FlickerList: React.FC<{
className={css` className={css`
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.5rem; gap: 0.8rem;
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
&:has(> li button:focus) li button:not(:focus), &:has(:focus) li button:not(:focus),
&:has(> li button:hover) li button:not(:hover) { &:has(:hover) li button:not(:hover) {
opacity: 0.5; opacity: 0.5;
} }
@ -184,9 +180,32 @@ const FlickerList: React.FC<{
className={css` className={css`
display: inline-block; display: inline-block;
`}> `}>
<Flicker index={index} description={item.description}> <Tooltip
description={item.description}
ref={async el => {
if (!el) return;
el.classList.add(invisible);
await sleep(500);
await sleep(300 * index);
el.classList.add(opaque);
await sleep(1000 + Math.random() * 1000);
tripleBlink(el);
while (true) {
await sleep(5000 + Math.random() * 10000);
const chosen =
opacities[Math.floor(Math.random() * opacities.length)];
el.classList.add(chosen);
await sleep(2000);
el.classList.remove(chosen);
tripleBlink(el);
}
}}>
{item.text} {item.text}
</Flicker> </Tooltip>
</li> </li>
)), )),
index => <li key={index}>·</li>, index => <li key={index}>·</li>,

Loading…
Cancel
Save