Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
eda2f920
Unverified
提交
eda2f920
authored
4月 26, 2025
作者:
Will Chen
提交者:
GitHub
4月 26, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support deep link for Dyad Pro (#25)
上级
4848b2f0
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
174 行增加
和
30 行删除
+174
-30
TitleBar.tsx
src/app/TitleBar.tsx
+55
-28
layout.tsx
src/app/layout.tsx
+1
-1
DyadProSuccessDialog.tsx
src/components/DyadProSuccessDialog.tsx
+52
-0
schemas.ts
src/lib/schemas.ts
+7
-1
main.ts
src/main.ts
+27
-0
pro.ts
src/main/pro.ts
+32
-0
没有找到文件。
src/app/TitleBar.tsx
浏览文件 @
eda2f920
...
...
@@ -8,11 +8,31 @@ import { Button } from "@/components/ui/button";
import
logo
from
"../../assets/logo_transparent.png"
;
import
{
providerSettingsRoute
}
from
"@/routes/settings/providers/$provider"
;
import
{
cn
}
from
"@/lib/utils"
;
import
{
useDeepLink
}
from
"@/contexts/DeepLinkContext"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
DyadProSuccessDialog
}
from
"@/components/DyadProSuccessDialog"
;
export
const
TitleBar
=
()
=>
{
const
[
selectedAppId
]
=
useAtom
(
selectedAppIdAtom
);
const
{
apps
}
=
useLoadApps
();
const
{
navigate
}
=
useRouter
();
const
{
settings
}
=
useSettings
();
const
{
settings
,
refreshSettings
}
=
useSettings
();
const
[
isSuccessDialogOpen
,
setIsSuccessDialogOpen
]
=
useState
(
false
);
const
showDyadProSuccessDialog
=
()
=>
{
setIsSuccessDialogOpen
(
true
);
};
const
{
lastDeepLink
}
=
useDeepLink
();
useEffect
(()
=>
{
const
handleDeepLink
=
async
()
=>
{
if
(
lastDeepLink
?.
type
===
"dyad-pro-return"
)
{
await
refreshSettings
();
showDyadProSuccessDialog
();
}
};
handleDeepLink
();
},
[
lastDeepLink
]);
// Get selected app name
const
selectedApp
=
apps
.
find
((
app
)
=>
app
.
id
===
selectedAppId
);
...
...
@@ -30,37 +50,44 @@ export const TitleBar = () => {
const
isDyadProEnabled
=
settings
?.
enableDyadPro
;
return
(
<
div
className=
"@container z-11 w-full h-11 bg-(--sidebar) absolute top-0 left-0 app-region-drag flex items-center"
>
<
div
className=
"pl-20"
></
div
>
<
img
src=
{
logo
}
alt=
"Dyad Logo"
className=
"w-6 h-6 mr-2"
/>
<
Button
variant=
"outline"
size=
"sm"
className=
{
`hidden @md:block no-app-region-drag text-sm font-medium ${
selectedApp ? "cursor-pointer" : ""
}`
}
onClick=
{
handleAppClick
}
>
{
displayText
}
</
Button
>
{
isDyadPro
&&
(
<>
<
div
className=
"@container z-11 w-full h-11 bg-(--sidebar) absolute top-0 left-0 app-region-drag flex items-center"
>
<
div
className=
"pl-20"
></
div
>
<
img
src=
{
logo
}
alt=
"Dyad Logo"
className=
"w-6 h-6 mr-2"
/>
<
Button
onClick=
{
()
=>
{
navigate
({
to
:
providerSettingsRoute
.
id
,
params
:
{
provider
:
"auto"
},
});
}
}
variant=
"outline"
className=
{
cn
(
"ml-4 no-app-region-drag h-7 bg-indigo-600 text-white dark:bg-indigo-600 dark:text-white"
,
!
isDyadProEnabled
&&
"bg-zinc-600 dark:bg-zinc-600"
)
}
size=
"sm"
className=
{
`hidden @md:block no-app-region-drag text-sm font-medium ${
selectedApp ? "cursor-pointer" : ""
}`
}
onClick=
{
handleAppClick
}
>
{
isDyadProEnabled
?
"Dyad Pro"
:
"Dyad Pro (disabled)"
}
{
displayText
}
</
Button
>
)
}
</
div
>
{
isDyadPro
&&
(
<
Button
onClick=
{
()
=>
{
navigate
({
to
:
providerSettingsRoute
.
id
,
params
:
{
provider
:
"auto"
},
});
}
}
variant=
"outline"
className=
{
cn
(
"ml-4 no-app-region-drag h-7 bg-indigo-600 text-white dark:bg-indigo-600 dark:text-white"
,
!
isDyadProEnabled
&&
"bg-zinc-600 dark:bg-zinc-600"
)
}
size=
"sm"
>
{
isDyadProEnabled
?
"Dyad Pro"
:
"Dyad Pro (disabled)"
}
</
Button
>
)
}
</
div
>
<
DyadProSuccessDialog
isOpen=
{
isSuccessDialogOpen
}
onClose=
{
()
=>
setIsSuccessDialogOpen
(
false
)
}
/>
</>
);
};
src/app/layout.tsx
浏览文件 @
eda2f920
...
...
@@ -12,10 +12,10 @@ export default function RootLayout({
})
{
return
(
<>
<
TitleBar
/>
<
ThemeProvider
>
<
DeepLinkProvider
>
<
SidebarProvider
>
<
TitleBar
/>
<
AppSidebar
/>
<
div
className=
"flex h-screenish w-full overflow-x-hidden mt-12 mb-4 mr-4 border-t border-l border-border rounded-lg bg-background"
>
{
children
}
...
...
src/components/DyadProSuccessDialog.tsx
0 → 100644
浏览文件 @
eda2f920
import
{
Dialog
,
DialogContent
,
DialogHeader
,
DialogTitle
,
DialogFooter
,
}
from
"@/components/ui/dialog"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
CheckCircle
,
Sparkles
}
from
"lucide-react"
;
interface
DyadProSuccessDialogProps
{
isOpen
:
boolean
;
onClose
:
()
=>
void
;
}
export
function
DyadProSuccessDialog
({
isOpen
,
onClose
,
}:
DyadProSuccessDialogProps
)
{
return
(
<
Dialog
open=
{
isOpen
}
onOpenChange=
{
onClose
}
>
<
DialogContent
className=
"max-w-md"
>
<
DialogHeader
>
<
DialogTitle
className=
"flex items-center gap-2 text-xl"
>
<
div
className=
"flex h-10 w-10 items-center justify-center rounded-full bg-green-100 dark:bg-green-900"
>
<
CheckCircle
className=
"h-6 w-6 text-green-600 dark:text-green-400"
/>
</
div
>
<
span
>
Dyad Pro Enabled
</
span
>
</
DialogTitle
>
</
DialogHeader
>
<
div
className=
"py-4"
>
<
p
className=
"mb-4 text-base"
>
Congrats! Dyad Pro is now enabled in the app.
</
p
>
<
div
className=
"flex items-center gap-2 mb-3"
>
<
Sparkles
className=
"h-5 w-5 text-indigo-500"
/>
<
p
className=
"text-sm"
>
You have access to leading AI models.
</
p
>
</
div
>
<
p
className=
"text-sm text-muted-foreground"
>
You can click the Pro button at the top to access the settings at
any time.
</
p
>
</
div
>
<
DialogFooter
className=
"flex justify-end gap-2"
>
<
Button
onClick=
{
onClose
}
variant=
"outline"
>
OK
</
Button
>
</
DialogFooter
>
</
DialogContent
>
</
Dialog
>
);
}
src/lib/schemas.ts
浏览文件 @
eda2f920
...
...
@@ -94,6 +94,12 @@ export const ExperimentsSchema = z.object({
});
export
type
Experiments
=
z
.
infer
<
typeof
ExperimentsSchema
>
;
export
const
DyadProBudgetSchema
=
z
.
object
({
budgetResetAt
:
z
.
string
(),
maxBudget
:
z
.
number
(),
});
export
type
DyadProBudget
=
z
.
infer
<
typeof
DyadProBudgetSchema
>
;
/**
* Zod schema for user settings
*/
...
...
@@ -108,7 +114,7 @@ export const UserSettingsSchema = z.object({
telemetryUserId
:
z
.
string
().
optional
(),
hasRunBefore
:
z
.
boolean
().
optional
(),
enableDyadPro
:
z
.
boolean
().
optional
(),
dyadProBudget
:
DyadProBudgetSchema
.
optional
(),
experiments
:
ExperimentsSchema
.
optional
(),
// DEPRECATED.
runtimeMode
:
RuntimeModeSchema
.
optional
(),
...
...
src/main.ts
浏览文件 @
eda2f920
...
...
@@ -8,6 +8,7 @@ import { updateElectronApp } from "update-electron-app";
import
log
from
"electron-log"
;
import
{
readSettings
,
writeSettings
}
from
"./main/settings"
;
import
{
handleSupabaseOAuthReturn
}
from
"./supabase_admin/supabase_return_handler"
;
import
{
handleDyadProReturn
}
from
"./main/pro"
;
log
.
errorHandler
.
startCatching
();
log
.
eventLogger
.
startLogging
();
...
...
@@ -185,6 +186,32 @@ function handleDeepLinkReturn(url: string) {
});
return
;
}
// dyad://dyad-pro-return?key=123&budget_reset_at=2025-05-26T16:31:13.492000Z&max_budget=100
if
(
parsed
.
hostname
===
"dyad-pro-return"
)
{
const
apiKey
=
parsed
.
searchParams
.
get
(
"key"
);
// UTC time
// budget_reset_at: '2025-05-26T16:31:13.492000Z'
const
budgetResetAt
=
parsed
.
searchParams
.
get
(
"budget_reset_at"
);
const
maxBudget
=
Number
(
parsed
.
searchParams
.
get
(
"max_budget"
));
if
(
!
apiKey
)
{
dialog
.
showErrorBox
(
"Invalid URL"
,
"Expected key, budget_reset_at, and max_budget"
);
return
;
}
handleDyadProReturn
({
apiKey
,
budgetResetAt
,
maxBudget
,
});
// Send message to renderer to trigger re-render
mainWindow
?.
webContents
.
send
(
"deep-link-received"
,
{
type
:
parsed
.
hostname
,
url
,
});
return
;
}
dialog
.
showErrorBox
(
"Invalid deep link URL"
,
url
);
}
...
...
src/main/pro.ts
0 → 100644
浏览文件 @
eda2f920
import
{
readSettings
,
writeSettings
}
from
"./settings"
;
export
function
handleDyadProReturn
({
apiKey
,
budgetResetAt
,
maxBudget
,
}:
{
apiKey
:
string
;
budgetResetAt
:
string
|
null
|
undefined
;
maxBudget
:
number
|
null
|
undefined
;
})
{
const
settings
=
readSettings
();
writeSettings
({
providerSettings
:
{
...
settings
.
providerSettings
,
auto
:
{
...
settings
.
providerSettings
.
auto
,
apiKey
:
{
value
:
apiKey
,
},
},
},
dyadProBudget
:
budgetResetAt
&&
maxBudget
?
{
budgetResetAt
,
maxBudget
,
}
:
undefined
,
enableDyadPro
:
true
,
});
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论