This commit is contained in:
Abhay Singh 2026-08-26 04:03:35 +05:30 committed by GitHub
commit 0d343e53b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 110 additions and 1 deletions

View file

@ -18,6 +18,12 @@ import { useLocalStorageUsername } from "@hooks/use-local-storage-username"
import { useHasCompanyBrain } from "@/hooks/use-company-brain"
import { toast } from "sonner"
import * as htmlToImage from "html-to-image"
import {
getShareAspectPreset,
SHARE_ASPECT_PRESETS,
type ShareAspect,
shareAspectMaxHeightDvh,
} from "@/lib/share-aspect"
type BackgroundTheme = "gradient" | "dark-gradient" | "black"
@ -281,9 +287,11 @@ export function ShareModal({
const isCompanyBrain = useHasCompanyBrain()
const [selectedTheme, setSelectedTheme] =
useState<BackgroundTheme>("gradient")
const [selectedAspect, setSelectedAspect] = useState<ShareAspect>("post")
const [isCopying, setIsCopying] = useState(false)
const [copied, setCopied] = useState(false)
const previewRef = useRef<HTMLDivElement>(null)
const aspectPreset = getShareAspectPreset(selectedAspect)
const localStorageUsername = useLocalStorageUsername()
const displayName =
@ -438,8 +446,10 @@ export function ShareModal({
{/* Preview area */}
<div
ref={previewRef}
className="relative w-full aspect-[674/505] max-h-[48dvh] rounded-[14px] overflow-hidden"
className="relative mx-auto w-full rounded-[14px] overflow-hidden"
style={{
aspectRatio: aspectPreset.ratio,
maxHeight: `${shareAspectMaxHeightDvh(selectedAspect)}dvh`,
boxShadow: "inset 2.42px 2.42px 4.26316px rgba(11, 15, 21, 0.7)",
}}
>
@ -493,6 +503,26 @@ export function ShareModal({
isSelected={selectedTheme === "black"}
onClick={() => setSelectedTheme("black")}
/>
<div className="mx-1 h-5 w-px bg-white/10" aria-hidden />
<div className="flex items-center gap-1 rounded-full bg-[#0D121A] p-0.5">
{SHARE_ASPECT_PRESETS.map((preset) => (
<button
key={preset.id}
type="button"
aria-pressed={selectedAspect === preset.id}
onClick={() => setSelectedAspect(preset.id)}
className={cn(
dmSansClassName(),
"h-6 rounded-full px-2.5 text-[11px] font-medium transition-colors",
selectedAspect === preset.id
? "bg-white/[0.12] text-white"
: "text-[#8B929E] hover:text-white",
)}
>
{preset.label}
</button>
))}
</div>
</div>
{/* Action buttons */}

View file

@ -0,0 +1,39 @@
import { describe, expect, it } from "bun:test"
import {
getShareAspectPreset,
SHARE_ASPECT_PRESETS,
shareAspectMaxHeightDvh,
type ShareAspect,
} from "./share-aspect"
describe("share-aspect presets", () => {
it("exposes post, square and story", () => {
expect(SHARE_ASPECT_PRESETS.map((p) => p.id)).toEqual([
"post",
"square",
"story",
])
})
it("resolves each preset by id", () => {
for (const preset of SHARE_ASPECT_PRESETS) {
expect(getShareAspectPreset(preset.id)).toBe(preset)
}
})
it("falls back to post for an unknown aspect", () => {
expect(getShareAspectPreset("nope" as ShareAspect).id).toBe("post")
})
it("has coherent ratio strings and numeric values", () => {
expect(getShareAspectPreset("square").value).toBe(1)
expect(getShareAspectPreset("post").value).toBeGreaterThan(1) // landscape
expect(getShareAspectPreset("story").value).toBeLessThan(1) // portrait
})
it("lets the narrow portrait story use more vertical space than the wide post", () => {
expect(shareAspectMaxHeightDvh("story")).toBeGreaterThan(
shareAspectMaxHeightDvh("post"),
)
})
})

View file

@ -0,0 +1,40 @@
/**
* Aspect-ratio presets for the graph share card, sized for where people post
* screenshots. Pure so the mapping can be unit tested.
*/
export type ShareAspect = "post" | "square" | "story"
export interface ShareAspectPreset {
id: ShareAspect
label: string
/** CSS `aspect-ratio` value (width / height). */
ratio: string
/** Width / height as a number, for any numeric layout math. */
value: number
}
const POST_PRESET: ShareAspectPreset = {
id: "post",
label: "Post",
ratio: "674 / 505",
value: 674 / 505,
}
export const SHARE_ASPECT_PRESETS: readonly ShareAspectPreset[] = [
POST_PRESET,
{ id: "square", label: "Square", ratio: "1 / 1", value: 1 },
{ id: "story", label: "Story", ratio: "9 / 16", value: 9 / 16 },
]
export function getShareAspectPreset(aspect: ShareAspect): ShareAspectPreset {
return SHARE_ASPECT_PRESETS.find((p) => p.id === aspect) ?? POST_PRESET
}
/**
* A max-height (in dvh) that keeps the preview inside the dialog. Tall (story)
* ratios need to be shorter than wide ones so they don't overflow.
*/
export function shareAspectMaxHeightDvh(aspect: ShareAspect): number {
return aspect === "story" ? 60 : 48
}