a tool for shared writing and social publishing
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

added a new theme color that is derived by calculating which accent color has the most contrast against the card bg. applied that to places in card that have accent coloring on hover

celine d2c9fc14 d06f7f8d

+92 -40
+1
app/globals.css
··· 12 12 13 13 --accent-1: 0, 0, 225; 14 14 --accent-2: 255, 255, 255; 15 + --accent-contrast: 0, 0, 225; 15 16 16 17 --highlight-1: 255, 177, 177; 17 18 --highlight-2: 253, 245, 203;
+7 -7
components/Blocks/BlockOptions.tsx
··· 46 46 <div className="blockOptionsContent flex gap-1 items-center"> 47 47 <ToolbarButton 48 48 tooltipContent="Add an Image" 49 - className="hover:bg-transparent hover:text-accent-1 text-tertiary" 49 + className="hover:bg-transparent hover:text-accent-contrast text-tertiary" 50 50 > 51 51 <label onMouseDown={(e) => e.preventDefault()}> 52 - <BlockImageSmall className="hover:text-accent-1" /> 52 + <BlockImageSmall className="hover:text-accent-contrast" /> 53 53 <div className="hidden"> 54 54 <input 55 55 type="file" ··· 92 92 93 93 <ToolbarButton 94 94 tooltipContent="Add a card" 95 - className="hover:bg-transparent hover:text-accent-1 text-tertiary" 95 + className="hover:bg-transparent hover:text-accent-constrast text-tertiary" 96 96 onClick={async () => { 97 97 if (!props.entityID) { 98 98 let entity = v7(); ··· 128 128 } 129 129 }} 130 130 > 131 - <BlockCardSmall className="hover:text-accent-1" /> 131 + <BlockCardSmall className="hover:text-accent-contrast" /> 132 132 </ToolbarButton> 133 133 </div> 134 134 </div> ··· 169 169 setLinkOpen(!linkOpen); 170 170 }} 171 171 > 172 - <BlockLinkSmall className="hover:text-accent-1" /> 172 + <BlockLinkSmall className="hover:text-accent-contrast" /> 173 173 </ToolbarButton> 174 174 175 175 {linkOpen && ( ··· 191 191 /> 192 192 <div className="flex items-center gap-3 "> 193 193 <button 194 - className="hover:text-accent-1" 194 + className="hover:text-accent-contrast" 195 195 onMouseDown={(e) => { 196 196 e.preventDefault(); 197 197 submit(); ··· 200 200 <CheckTiny /> 201 201 </button> 202 202 <button 203 - className="hover:text-accent-1" 203 + className="hover:text-accent-contrast" 204 204 onClick={() => setLinkOpen(false)} 205 205 > 206 206 <CloseTiny />
+1 -1
components/Blocks/CardBlock.tsx
··· 94 94 <CardPreview entityID={props.entityID} /> 95 95 {permission && ( 96 96 <button 97 - className="absolute p-1 top-0.5 right-0.5 hover:text-accent-1 text-secondary sm:hidden sm:group-hover/cardBlock:block" 97 + className="absolute p-1 top-0.5 right-0.5 hover:text-accent-contrast text-secondary sm:hidden sm:group-hover/cardBlock:block" 98 98 onClick={(e) => { 99 99 e.stopPropagation(); 100 100 setAreYouSure(true);
+4 -4
components/Blocks/ExternalLinkBlock.tsx
··· 22 22 className={` 23 23 externalLinkBlock flex relative group/linkBlock 24 24 h-[104px] bg-bg-card overflow-hidden text-primary no-underline 25 - border hover:border-accent-1 outline outline-1 hover:outline-accent-1 rounded-lg shadow-sm 26 - ${selected ? "outline-accent-1 border-accent-1" : "outline-transparent border-border-light"} 25 + border hover:border-accent-contrast outline outline-1 hover:outline-accent-contrast rounded-lg shadow-sm 26 + ${selected ? "outline-accent-contrast border-accent-contrast" : "outline-transparent border-border-light"} 27 27 `} 28 28 > 29 29 <div className="pt-2 pb-2 px-2 grow min-w-0"> ··· 40 40 {description?.data.value} 41 41 </div> 42 42 <div 43 - className={`inline-block place-self-end w-full text-xs italic line-clamp-1 truncate group-hover/linkBlock:text-accent-1 ${selected ? "text-accent-1" : "text-tertiary"}`} 43 + className={`inline-block place-self-end w-full text-xs italic line-clamp-1 truncate group-hover/linkBlock:text-accent-contrast ${selected ? "text-accent-contrast" : "text-tertiary"}`} 44 44 > 45 45 {url?.data.value} 46 46 </div> ··· 57 57 58 58 {permission && ( 59 59 <button 60 - className="absolute p-1 top-0.5 right-0.5 hover:text-accent-1 text-secondary sm:hidden sm:group-hover/linkBlock:block" 60 + className="absolute p-1 top-0.5 right-0.5 hover:text-accent-contrast text-secondary sm:hidden sm:group-hover/linkBlock:block" 61 61 onClick={(e) => { 62 62 e.preventDefault(); 63 63 e.stopPropagation();
+10 -6
components/ShareOptions/index.tsx
··· 63 63 } 64 64 }} 65 65 > 66 - <div> 67 - <div className="font-bold">Publish</div> 68 - <div className="text-sm text-tertiary"> 66 + <div className="group/publish"> 67 + <div className="font-bold group-hover/publish:text-accent-contrast"> 68 + Publish 69 + </div> 70 + <div className="text-sm text-tertiary group-hover/publish:text-accent-contrast"> 69 71 Share a read only version of this doc 70 72 </div> 71 73 </div> ··· 81 83 } 82 84 }} 83 85 > 84 - <div> 85 - <div className="font-bold">Collaborate</div> 86 - <div className="text-sm text-tertiary"> 86 + <div className="group/collab"> 87 + <div className="font-bold group-hover/collab:text-accent-contrast"> 88 + Collaborate 89 + </div> 90 + <div className="text-sm text-tertiary group-hover/collab:text-accent-contrast"> 87 91 Invite people to work together 88 92 </div> 89 93 </div>
+45 -8
components/ThemeManager/ThemeProvider.tsx
··· 2 2 3 3 import { CSSProperties, useEffect } from "react"; 4 4 import { colorToString, useColorAttribute } from "./useColorAttribute"; 5 - import { Color, parseColor } from "react-aria-components"; 5 + import { Color as AriaColor, parseColor } from "react-aria-components"; 6 + import { parse, contrastLstar, ColorSpace, sRGB } from "colorjs.io/fn"; 7 + 6 8 import { useEntity } from "src/replicache"; 7 9 8 10 type CSSVariables = { ··· 11 13 "--primary": string; 12 14 "--accent-1": string; 13 15 "--accent-2": string; 16 + "--accent-contrast": string; 14 17 "--highlight-1": string; 15 18 "--highlight-2": string; 16 19 "--highlight-3": string; ··· 28 31 // we just need to create a migration pipeline before we can change this 29 32 "theme/accent-text": "#FFFFFF", 30 33 "theme/accent-background": "#0000FF", 34 + "theme/accent-contrast": "#0000FF", 31 35 }; 32 36 33 - function setCSSVariableToColor(el: HTMLElement, name: string, value: Color) { 37 + function setCSSVariableToColor( 38 + el: HTMLElement, 39 + name: string, 40 + value: AriaColor, 41 + ) { 34 42 el?.style.setProperty(name, colorToString(value, "rgb")); 35 43 } 36 44 export function ThemeProvider(props: { ··· 40 48 let bgPage = useColorAttribute(props.entityID, "theme/page-background"); 41 49 let bgCard = useColorAttribute(props.entityID, "theme/card-background"); 42 50 let primary = useColorAttribute(props.entityID, "theme/primary"); 43 - let accent1 = useColorAttribute(props.entityID, "theme/accent-background"); 44 - let accent2 = useColorAttribute(props.entityID, "theme/accent-text"); 51 + 45 52 let backgroundImage = useEntity(props.entityID, "theme/background-image"); 46 53 let backgroundImageRepeat = useEntity( 47 54 props.entityID, ··· 50 57 let highlight1 = useEntity(props.entityID, "theme/highlight-1"); 51 58 let highlight2 = useColorAttribute(props.entityID, "theme/highlight-2"); 52 59 let highlight3 = useColorAttribute(props.entityID, "theme/highlight-3"); 60 + 61 + let accent1 = useColorAttribute(props.entityID, "theme/accent-background"); 62 + let accent2 = useColorAttribute(props.entityID, "theme/accent-text"); 63 + // set accent contrast to the accent color that has the highest contrast with the card background 64 + let accentContrast = [accent1, accent2].sort((a, b) => { 65 + return ( 66 + getColorContrast(colorToString(b, "rgb"), colorToString(bgCard, "rgb")) - 67 + getColorContrast(colorToString(a, "rgb"), colorToString(bgCard, "rgb")) 68 + ); 69 + })[0]; 70 + 71 + console.log("accentContrast", accentContrast); 53 72 54 73 useEffect(() => { 55 74 let el = document.querySelector(":root") as HTMLElement; ··· 61 80 bgCard.getChannelValue("alpha").toString(), 62 81 ); 63 82 setCSSVariableToColor(el, "--primary", primary); 64 - setCSSVariableToColor(el, "--accent-1", accent1); 65 - setCSSVariableToColor(el, "--accent-2", accent2); 83 + 66 84 setCSSVariableToColor(el, "--highlight-2", highlight2); 67 85 setCSSVariableToColor(el, "--highlight-3", highlight3); 68 86 ··· 79 97 "color-mix(in oklab, rgb(var(--primary)), rgb(var(--bg-card)) 75%)", 80 98 ); 81 99 } 100 + setCSSVariableToColor(el, "--accent-1", accent1); 101 + setCSSVariableToColor(el, "--accent-2", accent2); 102 + el?.style.setProperty( 103 + "--accent-contrast", 104 + colorToString(accentContrast, "rgb"), 105 + ); 106 + 107 + console.log(colorToString(accentContrast, "rgb")); 82 108 }, [ 83 109 bgPage, 84 110 bgCard, 85 111 primary, 86 - accent1, 87 - accent2, 88 112 highlight1, 89 113 highlight2, 90 114 highlight3, 115 + accent1, 116 + accent2, 117 + accentContrast, 91 118 ]); 92 119 return ( 93 120 <div ··· 105 132 "--primary": colorToString(primary, "rgb"), 106 133 "--accent-1": colorToString(accent1, "rgb"), 107 134 "--accent-2": colorToString(accent2, "rgb"), 135 + "--accent-contrast": colorToString(accentContrast, "rgb"), 108 136 "--highlight-1": highlight1 109 137 ? `rgb(${colorToString(parseColor(`hsba(${highlight1.data.value})`), "rgb")})` 110 138 : "color-mix(in oklab, rgb(var(--primary)), rgb(var(--bg-card)) 75%)", ··· 117 145 </div> 118 146 ); 119 147 } 148 + 149 + function getColorContrast(color1: string, color2: string) { 150 + ColorSpace.register(sRGB); 151 + 152 + let parsedColor1 = parse(`rgb(${color1})`); 153 + let parsedColor2 = parse(`rgb(${color2})`); 154 + 155 + return contrastLstar(parsedColor1, parsedColor2); 156 + }
+9 -7
components/ThemeManager/ThemeSetter.tsx
··· 68 68 props.entityID, 69 69 "theme/accent-background", 70 70 ); 71 - 71 + let accent2Value = useColorAttribute(props.entityID, "theme/accent-text"); 72 72 let permission = useEntitySetContext().permissions.write; 73 73 let backgroundImage = useEntity(props.entityID, "theme/background-image"); 74 74 let backgroundRepeat = useEntity( 75 75 props.entityID, 76 76 "theme/background-image-repeat", 77 77 ); 78 - let accent2Value = useColorAttribute(props.entityID, "theme/accent-text"); 78 + 79 79 let [openPicker, setOpenPicker] = useState<pickers>("null"); 80 80 let set = useMemo(() => { 81 81 return setColorAttribute(rep, props.entityID); ··· 223 223 <p className="font-bold">Hello!</p> 224 224 <small className=""> 225 225 Welcome to{" "} 226 - <span className="font-bold text-accent-1">Leaflet</span>. 227 - It&apos;s a super easy and fun way to make, share, and 226 + <span className="font-bold text-accent-contrast"> 227 + Leaflet 228 + </span> 229 + . It&apos;s a super easy and fun way to make, share, and 228 230 collab on little bits of paper 229 231 </small> 230 232 </div> ··· 232 234 </div> 233 235 <Popover.Arrow asChild width={16} height={8} viewBox="0 0 16 8"> 234 236 <PopoverArrow 235 - arrowFill={theme.colors["bg-card"]} 237 + arrowFill={theme.colors["white"]} 236 238 arrowStroke={theme.colors["border"]} 237 239 /> 238 240 </Popover.Arrow> ··· 438 440 </div> 439 441 </div> 440 442 <label className="hover:cursor-pointer h-fit"> 441 - <div className="text-[#8C8C8C] hover:text-accent-1"> 443 + <div className="text-[#8C8C8C] hover:text-[#0000FF]"> 442 444 <BlockImageSmall /> 443 445 </div> 444 446 <div className="hidden"> ··· 511 513 > 512 514 <label className="hover:cursor-pointer "> 513 515 <div 514 - className="flex gap-2 rounded-md px-2 py-1 text-accent-1 font-bold" 516 + className="flex gap-2 rounded-md px-2 py-1 text-accent-contrast font-bold" 515 517 style={{ backgroundColor: "rgba(var(--bg-card), .6" }} 516 518 > 517 519 <BlockImageSmall /> Change Image
+3 -3
components/Toolbar/HighlightButton.tsx
··· 117 117 collisionPadding={16} 118 118 > 119 119 <div 120 - className="bg-bg-page w-full mx-2 p-3 pb-0 my-3 flex flex-col rounded-md border border-border" 120 + className="bg-bg-page w-full m-2 p-3 pb-0 flex flex-col rounded-md border border-border" 121 121 style={{ 122 122 backgroundImage: `url(${backgroundImage?.data.src})`, 123 123 backgroundRepeat: backgroundRepeat ? "repeat" : "no-repeat", ··· 194 194 </div> 195 195 <Popover.Arrow asChild width={16} height={8} viewBox="0 0 16 8"> 196 196 <PopoverArrow 197 - arrowFill={theme.colors["bg-card"]} 197 + arrowFill={theme.colors["white"]} 198 198 arrowStroke={theme.colors["border"]} 199 199 /> 200 - </Popover.Arrow>{" "} 200 + </Popover.Arrow> 201 201 </Popover.Content> 202 202 </Popover.Portal> 203 203 </Popover.Root>
+2 -2
components/Toolbar/LinkButton.tsx
··· 36 36 }} 37 37 disabled={focusedEditor?.editor.selection.empty} 38 38 tooltipContent={ 39 - <div className="text-accent-1 underline">Inline Link</div> 39 + <div className="text-accent-contrast underline">Inline Link</div> 40 40 } 41 41 > 42 42 <LinkTextToolbarSmall /> ··· 115 115 */} 116 116 <div className="flex items-center gap-3"> 117 117 <button 118 - className="hover:text-accent-1 -mr-6" 118 + className="hover:text-accent-contrast -mr-6" 119 119 onMouseDown={(e) => { 120 120 e.preventDefault(); 121 121 let editor = focusedEditor?.editor;
+2 -2
components/Toolbar/index.tsx
··· 201 201 ) : null} 202 202 </div> 203 203 <button 204 - className="hover:text-accent-1" 204 + className="hover:text-accent-contrast" 205 205 onClick={() => { 206 206 if (toolbarState === "linkBlock") { 207 207 setToolbarState("block"); ··· 279 279 }} 280 280 /> 281 281 <button 282 - className="hover:text-accent-1 -mr-6" 282 + className="hover:text-accent-contrast -mr-6" 283 283 onMouseDown={(e) => { 284 284 e.preventDefault(); 285 285 submit();
+6
package-lock.json
··· 20 20 "@supabase/supabase-js": "^2.43.2", 21 21 "@vercel/kv": "^1.0.1", 22 22 "base64-js": "^1.5.1", 23 + "colorjs.io": "^0.5.2", 23 24 "drizzle-orm": "^0.30.10", 24 25 "fractional-indexing": "^3.2.0", 25 26 "next": "^14.2.4", ··· 6441 6442 "version": "1.1.4", 6442 6443 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 6443 6444 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 6445 + }, 6446 + "node_modules/colorjs.io": { 6447 + "version": "0.5.2", 6448 + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", 6449 + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==" 6444 6450 }, 6445 6451 "node_modules/combined-stream": { 6446 6452 "version": "1.0.8",
+1
package.json
··· 22 22 "@supabase/supabase-js": "^2.43.2", 23 23 "@vercel/kv": "^1.0.1", 24 24 "base64-js": "^1.5.1", 25 + "colorjs.io": "^0.5.2", 25 26 "drizzle-orm": "^0.30.10", 26 27 "fractional-indexing": "^3.2.0", 27 28 "next": "^14.2.4",
+1
tailwind.config.js
··· 33 33 //ACCENT COLORS 34 34 "accent-1": "rgb(var(--accent-1))", 35 35 "accent-2": "rgb(var(--accent-2))", 36 + "accent-contrast": "rgb(var(--accent-contrast))", 36 37 37 38 //BG COLORS (defined as css variables in global.css) 38 39 "bg-page": "rgb(var(--bg-page))",