feat: add About tab with developer profile and product links
New sidebar tab (⌘7) showing author info, AI coding philosophy quote, AtomStorm Studio product link, GitHub open-source link, and social channels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import AtlasDesignSystem
|
||||
import AtlasDomain
|
||||
import AtlasFeaturesAbout
|
||||
import AtlasFeaturesApps
|
||||
import AtlasFeaturesHistory
|
||||
import AtlasFeaturesOverview
|
||||
@@ -133,7 +134,21 @@ struct AppShellView: View {
|
||||
case .overview:
|
||||
OverviewFeatureView(
|
||||
snapshot: model.filteredSnapshot,
|
||||
isRefreshingHealthSnapshot: model.isHealthSnapshotRefreshing
|
||||
isRefreshingHealthSnapshot: model.isHealthSnapshotRefreshing,
|
||||
onStartSmartClean: {
|
||||
model.navigate(to: .smartClean)
|
||||
Task { await model.runSmartCleanScan() }
|
||||
},
|
||||
onNavigateToSmartClean: {
|
||||
model.navigate(to: .smartClean)
|
||||
},
|
||||
onNavigateToHistory: {
|
||||
model.navigate(to: .history)
|
||||
},
|
||||
onNavigateToPermissions: {
|
||||
model.navigate(to: .permissions)
|
||||
Task { await model.inspectPermissions() }
|
||||
}
|
||||
)
|
||||
case .smartClean:
|
||||
SmartCleanFeatureView(
|
||||
@@ -209,6 +224,8 @@ struct AppShellView: View {
|
||||
Task { await model.setNotificationsEnabled(isEnabled) }
|
||||
}
|
||||
)
|
||||
case .about:
|
||||
AboutFeatureView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,18 +240,7 @@ private struct SidebarRouteRow: View {
|
||||
let route: AtlasRoute
|
||||
|
||||
var body: some View {
|
||||
Label {
|
||||
VStack(alignment: .leading, spacing: AtlasSpacing.xxs) {
|
||||
Text(route.title)
|
||||
.font(AtlasTypography.rowTitle)
|
||||
|
||||
Text(route.subtitle)
|
||||
.font(AtlasTypography.captionSmall)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
} icon: {
|
||||
HStack(alignment: .center, spacing: AtlasSpacing.md) {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: AtlasRadius.sm, style: .continuous)
|
||||
.fill(AtlasColor.brand.opacity(0.1))
|
||||
@@ -245,6 +251,17 @@ private struct SidebarRouteRow: View {
|
||||
.foregroundStyle(AtlasColor.brand)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: AtlasSpacing.xxs) {
|
||||
Text(route.title)
|
||||
.font(AtlasTypography.rowTitle)
|
||||
|
||||
Text(route.subtitle)
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.tertiary)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, AtlasSpacing.sm)
|
||||
.contentShape(Rectangle())
|
||||
@@ -275,6 +292,8 @@ private extension AtlasRoute {
|
||||
return "5"
|
||||
case .settings:
|
||||
return "6"
|
||||
case .about:
|
||||
return "7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ public enum AtlasRoute: String, CaseIterable, Codable, Hashable, Identifiable, S
|
||||
case history
|
||||
case permissions
|
||||
case settings
|
||||
case about
|
||||
|
||||
public var id: String { rawValue }
|
||||
|
||||
@@ -24,6 +25,8 @@ public enum AtlasRoute: String, CaseIterable, Codable, Hashable, Identifiable, S
|
||||
return AtlasL10n.string("route.permissions.title")
|
||||
case .settings:
|
||||
return AtlasL10n.string("route.settings.title")
|
||||
case .about:
|
||||
return AtlasL10n.string("route.about.title")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +44,8 @@ public enum AtlasRoute: String, CaseIterable, Codable, Hashable, Identifiable, S
|
||||
return AtlasL10n.string("route.permissions.subtitle")
|
||||
case .settings:
|
||||
return AtlasL10n.string("route.settings.subtitle")
|
||||
case .about:
|
||||
return AtlasL10n.string("route.about.subtitle")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +63,8 @@ public enum AtlasRoute: String, CaseIterable, Codable, Hashable, Identifiable, S
|
||||
return "lock.shield"
|
||||
case .settings:
|
||||
return "gearshape"
|
||||
case .about:
|
||||
return "person.crop.circle"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
"route.permissions.subtitle" = "Explain why access is needed before asking for it.";
|
||||
"route.settings.title" = "Settings";
|
||||
"route.settings.subtitle" = "Preferences, exclusions, acknowledgement, and notices.";
|
||||
"route.about.title" = "About";
|
||||
"route.about.subtitle" = "Meet the developer and explore more products.";
|
||||
|
||||
"risk.safe" = "Safe";
|
||||
"risk.review" = "Review";
|
||||
@@ -244,6 +246,14 @@
|
||||
"overview.risk.safe" = "Low-risk cleanup";
|
||||
"overview.risk.review" = "Review before removing";
|
||||
"overview.risk.advanced" = "Advanced inspection recommended";
|
||||
"overview.actions.viewAll" = "View all %d findings";
|
||||
"overview.activity.viewAll" = "View all activity";
|
||||
"overview.snapshot.viewAllOptimizations" = "Show all %d suggestions";
|
||||
"overview.snapshot.collapseOptimizations" = "Collapse suggestions";
|
||||
"overview.action.smartClean" = "Run Smart Clean";
|
||||
"overview.action.smartClean.hint" = "Navigate to Smart Clean and start a scan.";
|
||||
"overview.action.permissions" = "Fix Permissions";
|
||||
"overview.action.permissions.hint" = "Navigate to Permissions to check and grant access.";
|
||||
|
||||
"smartclean.screen.title" = "Smart Clean";
|
||||
"smartclean.screen.subtitle" = "Turn scan results into a clear cleanup plan before you decide to run anything destructive.";
|
||||
@@ -559,3 +569,33 @@
|
||||
"settings.acknowledgement.subtitle" = "The in-app attribution text users can read without leaving the product.";
|
||||
"settings.notices.title" = "Third-Party Notices";
|
||||
"settings.notices.subtitle" = "A concise notice surface for shipped third-party attributions.";
|
||||
|
||||
"confirm.title" = "Confirm";
|
||||
"confirm.cancel" = "Cancel";
|
||||
"smartclean.confirm.execute.title" = "Run this cleanup plan?";
|
||||
"smartclean.confirm.execute.message" = "This will process the reviewed plan. Items marked recoverable can be restored from History.";
|
||||
"apps.confirm.uninstall.title" = "Uninstall this app?";
|
||||
"apps.confirm.uninstall.message" = "This will remove %@ and its leftovers. Recoverable items can be restored from History.";
|
||||
"emptystate.action.scan" = "Run Smart Clean";
|
||||
"emptystate.action.refresh" = "Refresh Apps";
|
||||
"emptystate.action.viewHistory" = "View History";
|
||||
"emptystate.action.startScan" = "Start Scan";
|
||||
"about.screen.title" = "About";
|
||||
"about.screen.subtitle" = "The person and vision behind Atlas for Mac.";
|
||||
"about.author.title" = "Developer";
|
||||
"about.author.name" = "Lizi KK";
|
||||
"about.author.role" = "Ex-Baidu & Alibaba Tech Lead · Hands On AI Coding";
|
||||
"about.author.bio" = "Built Atlas from 0 to 1 solo. Every line is AI-assisted, but passed through human decision-making, taste, and architectural judgment.";
|
||||
"about.author.quote" = "AI is incredibly powerful hands and feet, but you must be the clear-headed brain.";
|
||||
"about.product.title" = "Also by the Developer";
|
||||
"about.product.name" = "AtomStorm Studio";
|
||||
"about.product.detail" = "AI Agent-powered design platform — from idea to presentations, landing pages, and posters in minutes.";
|
||||
"about.product.visit" = "Visit AtomStorm Studio";
|
||||
"about.opensource.title" = "Open Source";
|
||||
"about.opensource.name" = "Atlas for Mac (Mole Installer)";
|
||||
"about.opensource.detail" = "This project is open source. Star, fork, or contribute on GitHub.";
|
||||
"about.opensource.visit" = "View on GitHub";
|
||||
"about.social.title" = "Follow Me";
|
||||
"about.social.detail" = "WeChat Official Account & Xiaohongshu";
|
||||
|
||||
"smartclean.preview.callout.review.title" = "Some steps in this plan need a closer review";
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
"route.permissions.subtitle" = "先解释原因,再请求访问。";
|
||||
"route.settings.title" = "设置";
|
||||
"route.settings.subtitle" = "偏好、排除项、致谢和通知。";
|
||||
"route.about.title" = "关于";
|
||||
"route.about.subtitle" = "了解作者,探索更多产品。";
|
||||
|
||||
"risk.safe" = "安全";
|
||||
"risk.review" = "复核";
|
||||
@@ -244,6 +246,14 @@
|
||||
"overview.risk.safe" = "低风险清理";
|
||||
"overview.risk.review" = "建议删除前先复核";
|
||||
"overview.risk.advanced" = "建议高级检查";
|
||||
"overview.actions.viewAll" = "查看全部 %d 项发现";
|
||||
"overview.activity.viewAll" = "查看全部活动";
|
||||
"overview.snapshot.viewAllOptimizations" = "展开全部 %d 条建议";
|
||||
"overview.snapshot.collapseOptimizations" = "收起建议";
|
||||
"overview.action.smartClean" = "运行智能清理";
|
||||
"overview.action.smartClean.hint" = "前往智能清理并开始扫描。";
|
||||
"overview.action.permissions" = "修复权限";
|
||||
"overview.action.permissions.hint" = "前往权限页面检查并授权。";
|
||||
|
||||
"smartclean.screen.title" = "智能清理";
|
||||
"smartclean.screen.subtitle" = "先把扫描结果变成清晰的清理计划,再决定是否执行任何具有破坏性的操作。";
|
||||
@@ -559,3 +569,33 @@
|
||||
"settings.acknowledgement.subtitle" = "用户无需离开产品,就能查看应用内致谢文本。";
|
||||
"settings.notices.title" = "第三方说明";
|
||||
"settings.notices.subtitle" = "用于展示随产品一起分发的第三方说明信息。";
|
||||
|
||||
"confirm.title" = "确认";
|
||||
"confirm.cancel" = "取消";
|
||||
"smartclean.confirm.execute.title" = "执行这份清理计划?";
|
||||
"smartclean.confirm.execute.message" = "将按复核后的计划执行清理。标记为可恢复的项目可以在历史中找回。";
|
||||
"apps.confirm.uninstall.title" = "卸载这个应用?";
|
||||
"apps.confirm.uninstall.message" = "将移除 %@ 及其残留文件。可恢复的项目可以在历史中找回。";
|
||||
"emptystate.action.scan" = "运行智能清理";
|
||||
"emptystate.action.refresh" = "刷新应用";
|
||||
"emptystate.action.viewHistory" = "查看历史";
|
||||
"emptystate.action.startScan" = "开始扫描";
|
||||
"about.screen.title" = "关于";
|
||||
"about.screen.subtitle" = "Atlas for Mac 背后的开发者与愿景。";
|
||||
"about.author.title" = "关于作者";
|
||||
"about.author.name" = "Lizi KK";
|
||||
"about.author.role" = "前百度 & 阿里技术负责人 · AI 全栈独立开发";
|
||||
"about.author.bio" = "从 0 到 1 独立构建 Atlas。每一行代码都由 AI 辅助,但都经过了人的决策、审美和架构判断。";
|
||||
"about.author.quote" = "AI 是极其强大的手和脚,但你必须做那个头脑清醒的大脑。";
|
||||
"about.product.title" = "作者的其他产品";
|
||||
"about.product.name" = "AtomStorm Studio";
|
||||
"about.product.detail" = "AI Agent 驱动的设计创作平台——从想法到演示文稿、落地页和海报,几分钟搞定。";
|
||||
"about.product.visit" = "访问 AtomStorm Studio";
|
||||
"about.opensource.title" = "开源项目";
|
||||
"about.opensource.name" = "Atlas for Mac (Mole Installer)";
|
||||
"about.opensource.detail" = "本项目已开源。欢迎在 GitHub 上 Star、Fork 或参与贡献。";
|
||||
"about.opensource.visit" = "在 GitHub 上查看";
|
||||
"about.social.title" = "关注作者";
|
||||
"about.social.detail" = "微信公众号 & 小红书";
|
||||
|
||||
"smartclean.preview.callout.review.title" = "这份计划中仍有步骤需要复核";
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import AtlasDesignSystem
|
||||
import AtlasDomain
|
||||
import SwiftUI
|
||||
|
||||
public struct AboutFeatureView: View {
|
||||
public init() {}
|
||||
|
||||
public var body: some View {
|
||||
AtlasScreen(
|
||||
title: AtlasL10n.string("about.screen.title"),
|
||||
subtitle: AtlasL10n.string("about.screen.subtitle")
|
||||
) {
|
||||
AtlasInfoCard(
|
||||
title: AtlasL10n.string("about.author.title")
|
||||
) {
|
||||
HStack(alignment: .center, spacing: AtlasSpacing.md) {
|
||||
Image(systemName: "person.crop.circle.fill")
|
||||
.font(.system(size: 40, weight: .light))
|
||||
.foregroundStyle(AtlasColor.brand)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
VStack(alignment: .leading, spacing: AtlasSpacing.xxs) {
|
||||
Text(AtlasL10n.string("about.author.name"))
|
||||
.font(AtlasTypography.sectionTitle)
|
||||
|
||||
Text(AtlasL10n.string("about.author.role"))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, AtlasSpacing.sm)
|
||||
|
||||
Text(AtlasL10n.string("about.author.bio"))
|
||||
.font(AtlasTypography.body)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
AtlasCallout(
|
||||
title: AtlasL10n.string("about.author.quote"),
|
||||
detail: AtlasL10n.string("about.author.name"),
|
||||
tone: .neutral,
|
||||
systemImage: "quote.opening"
|
||||
)
|
||||
|
||||
AtlasInfoCard(
|
||||
title: AtlasL10n.string("about.product.title")
|
||||
) {
|
||||
AtlasDetailRow(
|
||||
title: AtlasL10n.string("about.product.name"),
|
||||
subtitle: AtlasL10n.string("about.product.detail"),
|
||||
systemImage: "sparkle"
|
||||
)
|
||||
|
||||
Link(destination: URL(string: "https://studio.atomstorm.ai")!) {
|
||||
Text(AtlasL10n.string("about.product.visit"))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonStyle(.atlasPrimary)
|
||||
.padding(.top, AtlasSpacing.sm)
|
||||
}
|
||||
|
||||
AtlasInfoCard(
|
||||
title: AtlasL10n.string("about.opensource.title")
|
||||
) {
|
||||
AtlasDetailRow(
|
||||
title: AtlasL10n.string("about.opensource.name"),
|
||||
subtitle: AtlasL10n.string("about.opensource.detail"),
|
||||
systemImage: "chevron.left.forwardslash.chevron.right"
|
||||
)
|
||||
|
||||
Link(destination: URL(string: "https://github.com/CSZHK/mole-installer")!) {
|
||||
Text(AtlasL10n.string("about.opensource.visit"))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonStyle(.atlasSecondary)
|
||||
.padding(.top, AtlasSpacing.sm)
|
||||
}
|
||||
|
||||
AtlasInfoCard(
|
||||
title: AtlasL10n.string("about.social.title")
|
||||
) {
|
||||
HStack(spacing: AtlasSpacing.md) {
|
||||
Image(systemName: "ellipsis.bubble")
|
||||
.font(.title3)
|
||||
.foregroundStyle(AtlasColor.brand)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
Text(AtlasL10n.string("about.social.detail"))
|
||||
.font(AtlasTypography.body)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.accessibilityIdentifier("about.screen")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
AboutFeatureView()
|
||||
}
|
||||
@@ -14,6 +14,7 @@ let package = Package(
|
||||
.library(name: "AtlasFeaturesHistory", targets: ["AtlasFeaturesHistory"]),
|
||||
.library(name: "AtlasFeaturesOverview", targets: ["AtlasFeaturesOverview"]),
|
||||
.library(name: "AtlasFeaturesPermissions", targets: ["AtlasFeaturesPermissions"]),
|
||||
.library(name: "AtlasFeaturesAbout", targets: ["AtlasFeaturesAbout"]),
|
||||
.library(name: "AtlasFeaturesSettings", targets: ["AtlasFeaturesSettings"]),
|
||||
.library(name: "AtlasFeaturesSmartClean", targets: ["AtlasFeaturesSmartClean"]),
|
||||
.library(name: "AtlasFeaturesStorage", targets: ["AtlasFeaturesStorage"]),
|
||||
@@ -23,6 +24,7 @@ let package = Package(
|
||||
targets: [
|
||||
.target(
|
||||
name: "AtlasDesignSystem",
|
||||
dependencies: ["AtlasDomain"],
|
||||
path: "AtlasDesignSystem/Sources/AtlasDesignSystem",
|
||||
resources: [.process("Resources")]
|
||||
),
|
||||
@@ -62,6 +64,11 @@ let package = Package(
|
||||
dependencies: ["AtlasApplication", "AtlasDesignSystem", "AtlasDomain"],
|
||||
path: "AtlasFeaturesSmartClean/Sources/AtlasFeaturesSmartClean"
|
||||
),
|
||||
.target(
|
||||
name: "AtlasFeaturesAbout",
|
||||
dependencies: ["AtlasDesignSystem", "AtlasDomain"],
|
||||
path: "AtlasFeaturesAbout/Sources/AtlasFeaturesAbout"
|
||||
),
|
||||
.target(
|
||||
name: "AtlasFeaturesApps",
|
||||
dependencies: ["AtlasDesignSystem", "AtlasDomain"],
|
||||
|
||||
Reference in New Issue
Block a user