Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
37928a90
Unverified
提交
37928a90
authored
4月 29, 2025
作者:
Will Chen
提交者:
GitHub
4月 29, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Show release notes on startup (#44)
上级
c612017a
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
112 行增加
和
16 行删除
+112
-16
useAppVersion.ts
src/hooks/useAppVersion.ts
+20
-0
schemas.ts
src/lib/schemas.ts
+1
-0
home.tsx
src/pages/home.tsx
+85
-1
settings.tsx
src/pages/settings.tsx
+2
-14
globals.css
src/styles/globals.css
+4
-1
没有找到文件。
src/hooks/useAppVersion.ts
0 → 100644
浏览文件 @
37928a90
import
{
useState
,
useEffect
}
from
"react"
;
import
{
IpcClient
}
from
"@/ipc/ipc_client"
;
export
function
useAppVersion
()
{
const
[
appVersion
,
setAppVersion
]
=
useState
<
string
|
null
>
(
null
);
useEffect
(()
=>
{
const
fetchVersion
=
async
()
=>
{
try
{
const
version
=
await
IpcClient
.
getInstance
().
getAppVersion
();
setAppVersion
(
version
);
}
catch
(
error
)
{
setAppVersion
(
null
);
}
};
fetchVersion
();
},
[]);
return
appVersion
;
}
src/lib/schemas.ts
浏览文件 @
37928a90
...
...
@@ -117,6 +117,7 @@ export const UserSettingsSchema = z.object({
enableDyadPro
:
z
.
boolean
().
optional
(),
dyadProBudget
:
DyadProBudgetSchema
.
optional
(),
experiments
:
ExperimentsSchema
.
optional
(),
lastShownReleaseNotesVersion
:
z
.
string
().
optional
(),
// DEPRECATED.
runtimeMode
:
RuntimeModeSchema
.
optional
(),
});
...
...
src/pages/home.tsx
浏览文件 @
37928a90
...
...
@@ -14,6 +14,16 @@ import { HomeChatInput } from "@/components/chat/HomeChatInput";
import
{
usePostHog
}
from
"posthog-js/react"
;
import
{
PrivacyBanner
}
from
"@/components/TelemetryBanner"
;
import
{
INSPIRATION_PROMPTS
}
from
"@/prompts/inspiration_prompts"
;
import
{
useAppVersion
}
from
"@/hooks/useAppVersion"
;
import
{
Dialog
,
DialogContent
,
DialogHeader
,
DialogTitle
,
}
from
"@/components/ui/dialog"
;
import
{
useTheme
}
from
"@/contexts/ThemeContext"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
ExternalLink
}
from
"lucide-react"
;
export
default
function
HomePage
()
{
const
[
inputValue
,
setInputValue
]
=
useAtom
(
homeChatInputValueAtom
);
...
...
@@ -21,11 +31,40 @@ export default function HomePage() {
const
search
=
useSearch
({
from
:
"/"
});
const
setSelectedAppId
=
useSetAtom
(
selectedAppIdAtom
);
const
{
refreshApps
}
=
useLoadApps
();
const
{
settings
,
isAnyProviderSetup
}
=
useSettings
();
const
{
settings
,
updateSettings
}
=
useSettings
();
const
setIsPreviewOpen
=
useSetAtom
(
isPreviewOpenAtom
);
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
);
const
{
streamMessage
}
=
useStreamChat
({
hasChatId
:
false
});
const
posthog
=
usePostHog
();
const
appVersion
=
useAppVersion
();
const
[
releaseNotesOpen
,
setReleaseNotesOpen
]
=
useState
(
false
);
const
[
releaseUrl
,
setReleaseUrl
]
=
useState
(
""
);
const
{
theme
}
=
useTheme
();
useEffect
(()
=>
{
const
updateLastVersionLaunched
=
async
()
=>
{
if
(
appVersion
&&
appVersion
.
match
(
/^
\d
+
\.\d
+
\.\d
+$/
)
&&
settings
&&
settings
.
lastShownReleaseNotesVersion
!==
appVersion
)
{
await
updateSettings
({
lastShownReleaseNotesVersion
:
appVersion
,
});
// Check if release notes exist for this version
const
url
=
`https://www.dyad.sh/docs/releases/
${
appVersion
}
`
;
const
exists
=
await
checkPageExists
(
url
);
if
(
exists
)
{
setReleaseUrl
(
url
+
"?hideHeader=true&theme="
+
theme
);
setReleaseNotesOpen
(
true
);
}
}
};
updateLastVersionLaunched
();
},
[
appVersion
,
settings
,
updateSettings
]);
// Get the appId from search params
const
appId
=
search
.
appId
?
Number
(
search
.
appId
)
:
null
;
...
...
@@ -165,6 +204,51 @@ export default function HomePage() {
</
div
>
</
div
>
<
PrivacyBanner
/>
{
/* Release Notes Dialog */
}
<
Dialog
open=
{
releaseNotesOpen
}
onOpenChange=
{
setReleaseNotesOpen
}
>
<
DialogContent
className=
"max-w-4xl bg-(--docs-bg) pr-0 pt-4 pl-4 gap-1"
>
<
DialogHeader
>
<
DialogTitle
>
What's new in v
{
appVersion
}
?
</
DialogTitle
>
<
Button
variant=
"ghost"
size=
"sm"
className=
"absolute right-10 top-2 focus-visible:ring-0 focus-visible:ring-offset-0"
onClick=
{
()
=>
window
.
open
(
releaseUrl
.
replace
(
"?hideHeader=true&theme="
+
theme
,
""
),
"_blank"
)
}
>
<
ExternalLink
className=
"w-4 h-4"
/>
</
Button
>
</
DialogHeader
>
<
div
className=
"overflow-auto h-[70vh] flex flex-col "
>
{
releaseUrl
&&
(
<
div
className=
"flex-1"
>
<
iframe
src=
{
releaseUrl
}
className=
"w-full h-full border-0 rounded-lg"
title=
{
`Release notes for v${appVersion}`
}
/>
</
div
>
)
}
</
div
>
</
DialogContent
>
</
Dialog
>
</
div
>
);
}
function
checkPageExists
(
url
:
string
)
{
return
fetch
(
url
,
{
mode
:
"no-cors"
})
.
then
(()
=>
{
// Promise resolved - resource likely exists
return
true
;
})
.
catch
(()
=>
{
// Promise rejected - resource likely doesn't exist or network error
return
false
;
});
}
src/pages/settings.tsx
浏览文件 @
37928a90
...
...
@@ -7,6 +7,7 @@ import { showSuccess, showError } from "@/lib/toast";
import
{
AutoApproveSwitch
}
from
"@/components/AutoApproveSwitch"
;
import
{
TelemetrySwitch
}
from
"@/components/TelemetrySwitch"
;
import
{
useSettings
}
from
"@/hooks/useSettings"
;
import
{
useAppVersion
}
from
"@/hooks/useAppVersion"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
ArrowLeft
}
from
"lucide-react"
;
import
{
useRouter
}
from
"@tanstack/react-router"
;
...
...
@@ -16,23 +17,10 @@ export default function SettingsPage() {
const
{
theme
,
setTheme
}
=
useTheme
();
const
[
isResetDialogOpen
,
setIsResetDialogOpen
]
=
useState
(
false
);
const
[
isResetting
,
setIsResetting
]
=
useState
(
false
);
const
[
appVersion
,
setAppVersion
]
=
useState
<
string
|
null
>
(
null
);
const
appVersion
=
useAppVersion
(
);
const
{
settings
}
=
useSettings
();
const
router
=
useRouter
();
useEffect
(()
=>
{
// Fetch app version
const
fetchVersion
=
async
()
=>
{
try
{
const
version
=
await
IpcClient
.
getInstance
().
getAppVersion
();
setAppVersion
(
version
);
}
catch
(
error
)
{
setAppVersion
(
null
);
}
};
fetchVersion
();
},
[]);
const
handleResetEverything
=
async
()
=>
{
setIsResetting
(
true
);
try
{
...
...
src/styles/globals.css
浏览文件 @
37928a90
...
...
@@ -66,7 +66,7 @@
height
:
calc
(
100vh
-
64px
);
}
:root
{
--docs-bg
:
#f5f5f5
;
--default-font-family
:
'Geist'
,
sans-serif
;
--default-mono-font-family
:
'Geist Mono'
,
monospace
;
...
...
@@ -120,6 +120,9 @@
--tw-prose-pre-bg
:
var
(
--background
);
}
.dark
{
--docs-bg
:
#121212
;
--background-lightest
:
oklch
(
0.285
0
0
);
--background-lighter
:
oklch
(
0.185
0
0
);
--background
:
oklch
(
0.145
0
0
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论