mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-16 10:30:01 +08:00
feat(app): copy version from about settings
This commit is contained in:
@@ -1151,6 +1151,7 @@ export const dict = {
|
||||
"settings.tab.about": "About",
|
||||
"settings.about.version": "Version {{version}}",
|
||||
"settings.about.devVersion": "development",
|
||||
"settings.about.copyVersionFailed": "Failed to copy version",
|
||||
"settings.about.license": "Released under the MIT License",
|
||||
"settings.about.writtenBy": "Written by",
|
||||
"settings.about.illustratedBy": "Illustrated by",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { createResource } from "solid-js"
|
||||
import { Tooltip } from "@opencode/ui/tooltip"
|
||||
import { createEffect, createResource, onCleanup } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useLanguage } from "@/runtime/i18n/language"
|
||||
import { usePlatform } from "@/runtime/platform/platform"
|
||||
import { ExternalLink } from "@/runtime/platform/external-link"
|
||||
import { showToast } from "@/shell/notifications/toast"
|
||||
import legal from "./legal.svg"
|
||||
import anomalyBrush from "./anomaly-brush.svg"
|
||||
import { AnimatedWordmark } from "./animated-wordmark"
|
||||
@@ -30,11 +33,36 @@ const illustrators = ["usrnk1", "ludvigrask_", "arvsrn", "iamdavidhill"] as cons
|
||||
export function SettingsAbout(props: { active: boolean }) {
|
||||
const language = useLanguage()
|
||||
const platform = usePlatform()
|
||||
const [copy, setCopy] = createStore({ pending: false, copied: false, forceCopied: false })
|
||||
const version = () => platform.version ?? language.t("settings.about.devVersion")
|
||||
const versionLabel = () => language.t("settings.about.version", { version: version() })
|
||||
const [otherContributors] = createResource(
|
||||
() => props.active || undefined,
|
||||
() => loadOtherContributorCount(platform.fetch ?? fetch),
|
||||
{ initialValue: FALLBACK_OTHER_CONTRIBUTORS },
|
||||
)
|
||||
createEffect(() => {
|
||||
if (!copy.copied) return
|
||||
const close = setTimeout(() => setCopy("forceCopied", false), 2000)
|
||||
const reset = setTimeout(() => setCopy("copied", false), 2120)
|
||||
onCleanup(() => {
|
||||
clearTimeout(close)
|
||||
clearTimeout(reset)
|
||||
})
|
||||
})
|
||||
const copyVersion = async () => {
|
||||
if (copy.pending) return
|
||||
setCopy({ pending: true, copied: false, forceCopied: false })
|
||||
await (platform.writeClipboardText?.(versionLabel()) ?? navigator.clipboard.writeText(versionLabel()))
|
||||
.then(() => setCopy({ copied: true, forceCopied: true }))
|
||||
.catch(() =>
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: language.t("settings.about.copyVersionFailed"),
|
||||
}),
|
||||
)
|
||||
.finally(() => setCopy("pending", false))
|
||||
}
|
||||
const credit = (name: string) => (
|
||||
<bdi dir="ltr">
|
||||
<ExternalLink href={profile(name)}>{name}</ExternalLink>
|
||||
@@ -52,11 +80,27 @@ export function SettingsAbout(props: { active: boolean }) {
|
||||
return (
|
||||
<div class="settings-about-content">
|
||||
<div class="settings-about-intro">
|
||||
<p>
|
||||
{language.t("settings.about.version", {
|
||||
version: platform.version ?? language.t("settings.about.devVersion"),
|
||||
<div class="settings-about-version-line">
|
||||
<Tooltip
|
||||
value={language.t(copy.copied ? "common.copied" : "ui.message.copy")}
|
||||
placement="top"
|
||||
forceOpen={copy.forceCopied ? true : undefined}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="settings-about-version"
|
||||
disabled={copy.pending}
|
||||
aria-label={language.t(copy.copied ? "common.copied" : "ui.message.copy")}
|
||||
onClick={() => void copyVersion()}
|
||||
>
|
||||
<span>
|
||||
{language.rich("settings.about.version", {
|
||||
version: <bdi dir="ltr">{version()}</bdi>,
|
||||
})}
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p>{language.t("settings.about.license")}</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -233,6 +233,54 @@
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.settings-about-version-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.settings-about-version {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
align-items: center;
|
||||
margin-block: -2px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
transition: color 120ms ease;
|
||||
}
|
||||
|
||||
.settings-about-version::before {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
inset-block: 0;
|
||||
inset-inline: -6px;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
content: "";
|
||||
transition: background-color 120ms ease;
|
||||
}
|
||||
|
||||
.settings-about-version:hover,
|
||||
.settings-about-version:focus-visible {
|
||||
color: var(--v2-text-text-base);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.settings-about-version:hover::before,
|
||||
.settings-about-version:focus-visible::before {
|
||||
background: var(--v2-background-bg-layer-02);
|
||||
}
|
||||
|
||||
.settings-about-version:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.settings-about-credits,
|
||||
.settings-about-publication,
|
||||
.settings-about-details {
|
||||
|
||||
Reference in New Issue
Block a user