Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155import { createSignal, Index, Show } from "solid-js"import { Dialog } from "@opencode/ui/dialog"import { Button } from "@opencode/ui/button"import { useDialog } from "@opencode/ui/context/dialog"import { useLanguage } from "@/runtime/i18n/language"import { useSettings } from "@/settings/model"
export type Highlight = { title: string description: string media?: { type: "image" | "video" src: string alt?: string }}
export function DialogReleaseNotes(props: { highlights: Highlight[] }) { const dialog = useDialog() const language = useLanguage() const settings = useSettings() const [index, setIndex] = createSignal(0)
const total = () => props.highlights.length const last = () => Math.max(0, total() - 1) const feature = () => props.highlights[index()] ?? props.highlights[last()] const isFirst = () => index() === 0 const isLast = () => index() >= last() const paged = () => total() > 1
function handleNext() { if (isLast()) return setIndex(index() + 1) }
function handleClose() { dialog.close() }
function handleDisable() { settings.general.setReleaseNotes(false) handleClose() }
function handleKeyDown(e: KeyboardEvent) { if (e.key === "Escape") { e.preventDefault() handleClose() return }
if (!paged()) return if (e.key === "ArrowLeft" && !isFirst()) { e.preventDefault() setIndex(index() - 1) } if (e.key === "ArrowRight" && !isLast()) { e.preventDefault() setIndex(index() + 1) } }
return ( <Dialog size="large" fit class="w-[min(calc(100vw-40px),720px)] h-[min(calc(100vh-40px),400px)] -mt-20 min-h-0 overflow-hidden" > <div class="flex flex-1 min-w-0 min-h-0" tabIndex={0} autofocus onKeyDown={handleKeyDown}> {/* Left side - Text content */} <div class="flex flex-col flex-1 min-w-0 p-8"> {/* Top section - feature content (fixed position from top) */} <div class="flex flex-col gap-2 pt-22"> <div class="flex items-center gap-2"> <h1 class="text-16-medium text-text-strong">{feature()?.title ?? ""}</h1> </div> <p class="text-14-regular text-text-base">{feature()?.description ?? ""}</p> </div>
{/* Spacer to push buttons to bottom */} <div class="flex-1" />
{/* Bottom section - buttons and indicators (fixed position) */} <div class="flex flex-col gap-12"> <div class="flex flex-col items-start gap-3"> <Show when={isLast()} fallback={ <Button variant="neutral" size="large" onClick={handleNext}> {language.t("dialog.releaseNotes.action.next")} </Button> } > <Button variant="contrast" size="large" onClick={handleClose}> {language.t("dialog.releaseNotes.action.getStarted")} </Button> </Show>
<Button variant="ghost" size="small" onClick={handleDisable}> {language.t("dialog.releaseNotes.action.hideFuture")} </Button> </div>
<Show when={paged()}> <div class="flex items-center gap-1.5 -my-2.5"> <Index each={props.highlights}> {(_, i) => ( <button type="button" class="h-6 flex items-center cursor-pointer bg-transparent border-none p-0 transition-all duration-200" classList={{ "w-8": i === index(), "w-3": i !== index(), }} onClick={() => setIndex(i)} > <div class="w-full h-0.5 rounded-[1px] transition-colors duration-200" classList={{ "bg-icon-strong-base": i === index(), "bg-icon-weak-base": i !== index(), }} /> </button> )} </Index> </div> </Show> </div> </div>
{/* Right side - Media content (edge to edge) */} <Show when={feature()?.media}> {(media) => ( <div class="flex-1 min-w-0 bg-surface-base overflow-hidden rounded-r-xl"> <Show when={media().type === "image"} fallback={ <video src={media().src} autoplay loop muted playsinline class="w-full h-full object-cover" /> } > <img src={media().src} alt={media().alt ?? feature()?.title ?? language.t("dialog.releaseNotes.media.alt")} class="w-full h-full object-cover" /> </Show> </div> )} </Show> </div> </Dialog> )}