20 changed files with 2560 additions and 2789 deletions
@ -27,65 +27,64 @@ |
|||
"homepage": "https://meshtastic.org", |
|||
"dependencies": { |
|||
"@bufbuild/protobuf": "^1.10.0", |
|||
"@emeraldpay/hashicon-react": "^0.5.2", |
|||
"@meshtastic/js": "2.3.7-5", |
|||
"@noble/curves": "^1.5.0", |
|||
"@radix-ui/react-accordion": "^1.2.0", |
|||
"@radix-ui/react-checkbox": "^1.1.0", |
|||
"@radix-ui/react-dialog": "^1.1.1", |
|||
"@radix-ui/react-dropdown-menu": "^2.1.1", |
|||
"@radix-ui/react-label": "^2.1.0", |
|||
"@radix-ui/react-menubar": "^1.1.1", |
|||
"@radix-ui/react-popover": "^1.1.1", |
|||
"@radix-ui/react-scroll-area": "^1.1.0", |
|||
"@radix-ui/react-select": "^2.1.1", |
|||
"@radix-ui/react-separator": "^1.1.0", |
|||
"@radix-ui/react-switch": "^1.1.0", |
|||
"@radix-ui/react-tabs": "^1.1.0", |
|||
"@radix-ui/react-toast": "^1.2.1", |
|||
"@radix-ui/react-tooltip": "^1.1.1", |
|||
"@turf/turf": "^6.5.0", |
|||
"@noble/curves": "^1.8.1", |
|||
"@radix-ui/react-accordion": "^1.2.2", |
|||
"@radix-ui/react-checkbox": "^1.1.3", |
|||
"@radix-ui/react-dialog": "^1.1.5", |
|||
"@radix-ui/react-dropdown-menu": "^2.1.5", |
|||
"@radix-ui/react-label": "^2.1.1", |
|||
"@radix-ui/react-menubar": "^1.1.5", |
|||
"@radix-ui/react-popover": "^1.1.5", |
|||
"@radix-ui/react-scroll-area": "^1.2.2", |
|||
"@radix-ui/react-select": "^2.1.5", |
|||
"@radix-ui/react-separator": "^1.1.1", |
|||
"@radix-ui/react-switch": "^1.1.2", |
|||
"@radix-ui/react-tabs": "^1.1.2", |
|||
"@radix-ui/react-toast": "^1.2.5", |
|||
"@radix-ui/react-tooltip": "^1.1.7", |
|||
"@turf/turf": "^7.2.0", |
|||
"base64-js": "^1.5.1", |
|||
"class-validator": "^0.14.1", |
|||
"class-variance-authority": "^0.7.0", |
|||
"class-variance-authority": "^0.7.1", |
|||
"clsx": "^2.1.1", |
|||
"cmdk": "^1.0.0", |
|||
"cmdk": "^1.0.4", |
|||
"crypto-random-string": "^5.0.0", |
|||
"immer": "^10.1.1", |
|||
"js-cookie": "^3.0.5", |
|||
"lucide-react": "^0.363.0", |
|||
"mapbox-gl": "^3.6.0", |
|||
"lucide-react": "^0.474.0", |
|||
"mapbox-gl": "^3.9.4", |
|||
"maplibre-gl": "4.1.2", |
|||
"react": "^18.3.1", |
|||
"react-dom": "^18.3.1", |
|||
"react-hook-form": "^7.52.0", |
|||
"react-map-gl": "7.1.7", |
|||
"react-qrcode-logo": "^2.10.0", |
|||
"rfc4648": "^1.5.3", |
|||
"react": "^19.0.0", |
|||
"react-dom": "^19.0.0", |
|||
"react-hook-form": "^7.54.2", |
|||
"react-map-gl": "7.1.9", |
|||
"react-qrcode-logo": "^3.0.0", |
|||
"rfc4648": "^1.5.4", |
|||
"timeago-react": "^3.0.6", |
|||
"vite-plugin-node-polyfills": "^0.22.0", |
|||
"zustand": "4.5.2" |
|||
"vite-plugin-node-polyfills": "^0.23.0", |
|||
"zustand": "5.0.3" |
|||
}, |
|||
"devDependencies": { |
|||
"@biomejs/biome": "^1.8.2", |
|||
"@rsbuild/core": "^1.0.10", |
|||
"@rsbuild/plugin-react": "^1.0.3", |
|||
"@types/chrome": "^0.0.263", |
|||
"@biomejs/biome": "^1.9.4", |
|||
"@rsbuild/core": "^1.2.3", |
|||
"@rsbuild/plugin-react": "^1.1.0", |
|||
"@types/chrome": "^0.0.299", |
|||
"@types/js-cookie": "^3.0.6", |
|||
"@types/node": "^20.14.9", |
|||
"@types/react": "^18.3.3", |
|||
"@types/react-dom": "^18.3.0", |
|||
"@types/w3c-web-serial": "^1.0.6", |
|||
"@types/node": "^22.12.0", |
|||
"@types/react": "^19.0.8", |
|||
"@types/react-dom": "^19.0.3", |
|||
"@types/w3c-web-serial": "^1.0.7", |
|||
"@types/web-bluetooth": "^0.0.20", |
|||
"autoprefixer": "^10.4.19", |
|||
"gzipper": "^7.2.0", |
|||
"postcss": "^8.4.38", |
|||
"autoprefixer": "^10.4.20", |
|||
"gzipper": "^8.2.0", |
|||
"postcss": "^8.5.1", |
|||
"simple-git-hooks": "^2.11.1", |
|||
"tailwind-merge": "^2.3.0", |
|||
"tailwindcss": "^3.4.4", |
|||
"tailwind-merge": "^2.6.0", |
|||
"tailwindcss": "^3.4.17", |
|||
"tailwindcss-animate": "^1.0.7", |
|||
"tar": "^6.2.1", |
|||
"typescript": "^5.5.2" |
|||
"tar": "^7.4.3", |
|||
"typescript": "^5.7.3" |
|||
}, |
|||
"packageManager": "[email protected]" |
|||
} |
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,94 @@ |
|||
import { cn } from "@app/core/utils/cn"; |
|||
import type React from "react"; |
|||
|
|||
type RGBColor = { |
|||
r: number; |
|||
g: number; |
|||
b: number; |
|||
a: number; |
|||
}; |
|||
|
|||
interface AvatarProps { |
|||
text: string; |
|||
size?: "sm" | "lg"; |
|||
className?: string; |
|||
} |
|||
|
|||
// biome-ignore lint/complexity/noStaticOnlyClass: stop being annoying Biome
|
|||
class ColorUtils { |
|||
static hexToRgb(hex: number): RGBColor { |
|||
return { |
|||
r: (hex & 0xff0000) >> 16, |
|||
g: (hex & 0x00ff00) >> 8, |
|||
b: hex & 0x0000ff, |
|||
a: 255, |
|||
}; |
|||
} |
|||
|
|||
static rgbToHex(color: RGBColor): number { |
|||
return ( |
|||
(Math.round(color.a) << 24) | |
|||
(Math.round(color.r) << 16) | |
|||
(Math.round(color.g) << 8) | |
|||
Math.round(color.b) |
|||
); |
|||
} |
|||
|
|||
static isLight(color: RGBColor): boolean { |
|||
const brightness = (color.r * 299 + color.g * 587 + color.b * 114) / 1000; |
|||
return brightness > 127.5; |
|||
} |
|||
} |
|||
|
|||
export const Avatar: React.FC<AvatarProps> = ({ |
|||
text, |
|||
size = "sm", |
|||
className, |
|||
}) => { |
|||
const sizes = { |
|||
sm: "size-11 text-xs", |
|||
lg: "size-16 text-lg", |
|||
}; |
|||
|
|||
// Pick a color based on the text provided to function
|
|||
const getColorFromText = (text: string): RGBColor => { |
|||
let hash = 0; |
|||
for (let i = 0; i < text.length; i++) { |
|||
hash = text.charCodeAt(i) + ((hash << 5) - hash); |
|||
} |
|||
|
|||
return { |
|||
r: (hash & 0xff0000) >> 16, |
|||
g: (hash & 0x00ff00) >> 8, |
|||
b: hash & 0x0000ff, |
|||
a: 255, |
|||
}; |
|||
}; |
|||
|
|||
const bgColor = getColorFromText(text ?? "UNK"); |
|||
const isLight = ColorUtils.isLight(bgColor); |
|||
const textColor = isLight ? "#000000" : "#FFFFFF"; |
|||
const initials = text?.toUpperCase().slice(0, 4) ?? "UNK"; |
|||
|
|||
return ( |
|||
<div |
|||
className={cn( |
|||
` |
|||
rounded-full |
|||
flex |
|||
items-center |
|||
justify-center |
|||
size-11 |
|||
font-semibold`,
|
|||
sizes[size], |
|||
className, |
|||
)} |
|||
style={{ |
|||
backgroundColor: `rgb(${bgColor.r}, ${bgColor.g}, ${bgColor.b})`, |
|||
color: textColor, |
|||
}} |
|||
> |
|||
<p className="p-1">{initials}</p> |
|||
</div> |
|||
); |
|||
}; |
|||
Loading…
Reference in new issue