bd0cead00e
leo 2026-08-04 看過 v0.16.0 畫面後:
「功能都有了,但美感非常糟糕⋯⋯跟 CIS 完全無關,每個功能都開一個小小的 popup 視窗,
非常缺乏整體感,這要理解的是原始的技術選擇是否出錯?」
「我的要求是符合 CIS,在風格上跟 portal 一樣」
「CIS 已經提供規範,你做的連 Logo 都沒放上去,這跟美不美有關係嗎?
要求放進 CIS 是硬要求,你做為檢查有嗎?沒有怎麼交貨?」
## 我的兩個錯
1. **動工前沒提醒做不到**——decisions-summary.md:314 的 D-daemon-UI
是我 07-27 自己寫的調研(結論:fyne 全自繪、CSS 套不進去),寫完就沒再看。
今天動工前該查它卻直接開寫,浪費 leo 的時間與 token。
2. **沒做 CIS 檢查就交貨**——連 logo 都沒放。
## 換 Wails(WebView 殼)
前端就是 HTML/CSS ⇒ 可以直接用 portal 那份色票與 lockup。
- style.css 的色票/字體/紙張紋理**逐字取自** portal 的 :root
(matrix/arcrun:console-ui/public/portal/index.html),不自創任何顏色
- CIS lockup 官方 PNG,淺色 ink 版/深色 paper 版,切換規則同 portal
(避開 08-01 作廢的自產 SVG——字腔缺失)
- 對話框改**內嵌覆蓋層**,不再每個功能開一個小 popup
- 原生資料夾選擇器(macOS powerbox 會自動授予該資料夾存取權,
fyne 自繪 picker 拿不到;未來上 Mac App Store 是硬需求)
- 同步中的圓點會呼吸 ⇒ 看得出來在動(issue #17)
- 無帳號時是 onboarding 引導,不是空白面板
## 連線邏輯逐字沿用,不重寫
connect.go 的 normalizePortalURL/fetchConfigByLogin 取自 arcrun-tray/main.go,
含 t86 個資外洩事故的防線(不同實例=新增帳號,絕不覆蓋舊帳號的資料夾)。
今天已犯過一次「重寫別人修好的東西還修得更差」,不再犯第二次。
## 新增 check-cis.sh(交貨前必跑)
機械檢查六類:官方色票逐個到齊/**不准出現非 CIS 色**/logo 真的放進去/
不可用作廢 SVG/深色模式/字體與紙張紋理同 portal/app icon。
實跑 14 項全過。以後「沒跑過就不准交」。
⚠️ 未驗:實際畫面要 leo 開來看(我開不了視窗)。
285 lines
9.7 KiB
NSIS
285 lines
9.7 KiB
NSIS
# DO NOT EDIT - Generated automatically by `wails build`
|
|
|
|
!include "x64.nsh"
|
|
!include "WinVer.nsh"
|
|
!include "FileFunc.nsh"
|
|
|
|
!ifndef INFO_PROJECTNAME
|
|
!define INFO_PROJECTNAME "{{.Name}}"
|
|
!endif
|
|
!ifndef INFO_COMPANYNAME
|
|
!define INFO_COMPANYNAME "{{.Info.CompanyName}}"
|
|
!endif
|
|
!ifndef INFO_PRODUCTNAME
|
|
!define INFO_PRODUCTNAME "{{.Info.ProductName}}"
|
|
!endif
|
|
!ifndef INFO_PRODUCTVERSION
|
|
!define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}"
|
|
!endif
|
|
!ifndef INFO_COPYRIGHT
|
|
!define INFO_COPYRIGHT "{{.Info.Copyright}}"
|
|
!endif
|
|
!ifndef PRODUCT_EXECUTABLE
|
|
!define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
|
|
!endif
|
|
!ifndef UNINST_KEY_NAME
|
|
!define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
|
|
!endif
|
|
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
|
|
|
|
!ifndef REQUEST_EXECUTION_LEVEL
|
|
!define REQUEST_EXECUTION_LEVEL "admin"
|
|
!endif
|
|
|
|
RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
|
|
|
|
!ifdef ARG_WAILS_AMD64_BINARY
|
|
!define SUPPORTS_AMD64
|
|
!endif
|
|
|
|
!ifdef ARG_WAILS_ARM64_BINARY
|
|
!define SUPPORTS_ARM64
|
|
!endif
|
|
|
|
!ifdef SUPPORTS_AMD64
|
|
!ifdef SUPPORTS_ARM64
|
|
!define ARCH "amd64_arm64"
|
|
!else
|
|
!define ARCH "amd64"
|
|
!endif
|
|
!else
|
|
!ifdef SUPPORTS_ARM64
|
|
!define ARCH "arm64"
|
|
!else
|
|
!error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY"
|
|
!endif
|
|
!endif
|
|
|
|
!macro wails.checkArchitecture
|
|
!ifndef WAILS_WIN10_REQUIRED
|
|
!define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later."
|
|
!endif
|
|
|
|
!ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED
|
|
!define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}"
|
|
!endif
|
|
|
|
${If} ${AtLeastWin10}
|
|
!ifdef SUPPORTS_AMD64
|
|
${if} ${IsNativeAMD64}
|
|
Goto ok
|
|
${EndIf}
|
|
!endif
|
|
|
|
!ifdef SUPPORTS_ARM64
|
|
${if} ${IsNativeARM64}
|
|
Goto ok
|
|
${EndIf}
|
|
!endif
|
|
|
|
IfSilent silentArch notSilentArch
|
|
silentArch:
|
|
SetErrorLevel 65
|
|
Abort
|
|
notSilentArch:
|
|
MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}"
|
|
Quit
|
|
${else}
|
|
IfSilent silentWin notSilentWin
|
|
silentWin:
|
|
SetErrorLevel 64
|
|
Abort
|
|
notSilentWin:
|
|
MessageBox MB_OK "${WAILS_WIN10_REQUIRED}"
|
|
Quit
|
|
${EndIf}
|
|
|
|
ok:
|
|
!macroend
|
|
|
|
!macro wails.files
|
|
!ifdef SUPPORTS_AMD64
|
|
${if} ${IsNativeAMD64}
|
|
File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}"
|
|
${EndIf}
|
|
!endif
|
|
|
|
!ifdef SUPPORTS_ARM64
|
|
${if} ${IsNativeARM64}
|
|
File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}"
|
|
${EndIf}
|
|
!endif
|
|
!macroend
|
|
|
|
!macro wails.writeUninstaller
|
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
|
|
|
SetRegView 64
|
|
!ifdef WAILS_INSTALL_SCOPE
|
|
!if "${WAILS_INSTALL_SCOPE}" == "user"
|
|
WriteRegStr HKCU "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
|
|
WriteRegStr HKCU "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
|
|
WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
|
|
WriteRegStr HKCU "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
|
|
WriteRegStr HKCU "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
|
|
WriteRegStr HKCU "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
|
|
!else
|
|
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
|
|
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
|
|
!endif
|
|
!else
|
|
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
|
|
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
|
|
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
|
|
!endif
|
|
|
|
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
|
IntFmt $0 "0x%08X" $0
|
|
|
|
!ifdef WAILS_INSTALL_SCOPE
|
|
!if "${WAILS_INSTALL_SCOPE}" == "user"
|
|
WriteRegDWORD HKCU "${UNINST_KEY}" "EstimatedSize" "$0"
|
|
!else
|
|
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
|
|
!endif
|
|
!else
|
|
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
|
|
!endif
|
|
!macroend
|
|
|
|
!macro wails.deleteUninstaller
|
|
Delete "$INSTDIR\uninstall.exe"
|
|
|
|
SetRegView 64
|
|
|
|
!ifdef WAILS_INSTALL_SCOPE
|
|
!if "${WAILS_INSTALL_SCOPE}" == "user"
|
|
DeleteRegKey HKCU "${UNINST_KEY}"
|
|
!else
|
|
DeleteRegKey HKLM "${UNINST_KEY}"
|
|
!endif
|
|
!else
|
|
DeleteRegKey HKLM "${UNINST_KEY}"
|
|
!endif
|
|
!macroend
|
|
|
|
!macro wails.setShellContext
|
|
${If} ${REQUEST_EXECUTION_LEVEL} == "admin"
|
|
SetShellVarContext all
|
|
${else}
|
|
SetShellVarContext current
|
|
${EndIf}
|
|
!macroend
|
|
|
|
# Install webview2 by launching the bootstrapper
|
|
# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
|
|
!macro wails.webview2runtime
|
|
!ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT
|
|
!define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime"
|
|
!endif
|
|
|
|
SetRegView 64
|
|
# If the admin key exists and is not empty then webview2 is already installed
|
|
ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
|
|
${If} $0 != ""
|
|
Goto ok
|
|
${EndIf}
|
|
|
|
${If} ${REQUEST_EXECUTION_LEVEL} == "user"
|
|
# If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed
|
|
ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
|
|
${If} $0 != ""
|
|
Goto ok
|
|
${EndIf}
|
|
${EndIf}
|
|
|
|
SetDetailsPrint both
|
|
DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}"
|
|
SetDetailsPrint listonly
|
|
|
|
InitPluginsDir
|
|
CreateDirectory "$pluginsdir\webview2bootstrapper"
|
|
SetOutPath "$pluginsdir\webview2bootstrapper"
|
|
File "tmp\MicrosoftEdgeWebview2Setup.exe"
|
|
ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install'
|
|
|
|
SetDetailsPrint both
|
|
ok:
|
|
!macroend
|
|
|
|
# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b
|
|
!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
|
|
; Backup the previously associated file class
|
|
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"
|
|
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open"
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}`
|
|
!macroend
|
|
|
|
!macro APP_UNASSOCIATE EXT FILECLASS
|
|
; Backup the previously associated file class
|
|
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup`
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0"
|
|
|
|
DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}`
|
|
!macroend
|
|
|
|
!macro wails.associateFiles
|
|
; Create file associations
|
|
{{range .Info.FileAssociations}}
|
|
!insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
|
|
|
|
File "..\{{.IconName}}.ico"
|
|
{{end}}
|
|
!macroend
|
|
|
|
!macro wails.unassociateFiles
|
|
; Delete app associations
|
|
{{range .Info.FileAssociations}}
|
|
!insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}"
|
|
|
|
Delete "$INSTDIR\{{.IconName}}.ico"
|
|
{{end}}
|
|
!macroend
|
|
|
|
!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND
|
|
DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
|
|
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
|
|
!macroend
|
|
|
|
!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL
|
|
DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
|
|
!macroend
|
|
|
|
!macro wails.associateCustomProtocols
|
|
; Create custom protocols associations
|
|
{{range .Info.Protocols}}
|
|
!insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
|
|
|
|
{{end}}
|
|
!macroend
|
|
|
|
!macro wails.unassociateCustomProtocols
|
|
; Delete app custom protocol associations
|
|
{{range .Info.Protocols}}
|
|
!insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
|
|
{{end}}
|
|
!macroend
|