SPB Git

spb/ka-macos

Public

v2.0.0 — logos officiels des 13 marques + sites web intégrés (WKWebView)

- Logos ka-ui (512 px) embarqués en ressources SwiftPM (Bundle.module),
  helper KALogo avec repli symbole SF : sidebar, accueil, héros
  d'explorateur, pouls du MenuBarExtra.
- SiteView : navigateur WKWebView intégré (retour/avancer, recharger,
  domaine courant, partager, ouvrir dans le navigateur, progression
  teintée accent) ; tel:/mailto: vers le système ; target=_blank
  gardé dans la vue.
- Bascule « Données | Site » dans la barre d'outils de chaque univers ;
  entrée sidebar + menu Univers « groupe-ka.com » (hub intégré).
- package-app.sh copie le bundle de ressources SPM ; version 2.0.0 (2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Aug 21, 2026) parent e2e01af Browse files

23 changed files +295 −43

modified Package.swift +1 −0
@@ -11,6 +11,7 @@ let package = Package(
11 .executableTarget( 11 .executableTarget(
12 name: "KA", 12 name: "KA",
13 path: "Sources/KA", 13 path: "Sources/KA",
14+ resources: [.copy("Resources/Logos")],
14 linkerSettings: [.linkedFramework("Carbon")] 15 linkerSettings: [.linkedFramework("Carbon")]
15 ) 16 )
16 ] 17 ]
modified Sources/KA/App/KAApp.swift +15 −0
@@ -12,6 +12,8 @@ enum SidebarSelection: Hashable {
12 case home, search, map, agent, status 12 case home, search, map, agent, status
13 case favorites, history, alerts 13 case favorites, history, alerts
14 case universe(String) 14 case universe(String)
15+ /// Le site du hub groupe-ka.com, intégré (WKWebView).
16+ case hub
15 } 17 }
16 18
17 @MainActor 19 @MainActor
@@ -178,6 +180,8 @@ struct KAApp: App {
178 ForEach(Array(Ecosystem.all.enumerated()), id: \.element.id) { i, u in 180 ForEach(Array(Ecosystem.all.enumerated()), id: \.element.id) { i, u in
179 UniverseCommand(universe: u, index: i) 181 UniverseCommand(universe: u, index: i)
180 } 182 }
183+ Divider()
184+ HubCommand()
181 } 185 }
182 } 186 }
183 187
@@ -255,6 +259,17 @@ private struct SearchCommands: View {
255 } 259 }
256 } 260 }
257 261
262+/// Le hub groupe-ka.com, intégré dans l'app (menu Univers).
263+private struct HubCommand: View {
264+ @Environment(\.openWindow) private var openWindow
265+ var body: some View {
266+ Button("groupe-ka.com — le hub") {
267+ focusMainWindow(openWindow)
268+ AppState.shared.selection = .hub
269+ }
270+ }
271+}
272+
258 /// Menu « Univers » : ⌘1..⌘9 pour les 9 premiers. 273 /// Menu « Univers » : ⌘1..⌘9 pour les 9 premiers.
259 private struct UniverseCommand: View { 274 private struct UniverseCommand: View {
260 let universe: Universe 275 let universe: Universe
modified Sources/KA/DesignMac/Theme.swift +41 −0
@@ -95,6 +95,47 @@ struct GroupeKAMark: View {
95 } 95 }
96 } 96 }
97 97
98+// MARK: - Logo officiel d'une marque (PNG ka-ui embarqué, repli symbole SF)
99+
100+/// Vrai logo de la marque (tuile encre + « Ka » accent, rendu depuis ka-ui).
101+/// `id` = id d'univers (« lou-ka »…) ou « groupe-ka » pour le hub.
102+struct KALogo: View {
103+ let id: String
104+ var size: CGFloat = 20
105+ /// Repli si le PNG manque (ex. id inconnu) — symbole SF teinté accent.
106+ var fallbackSymbol: String = "square.grid.2x2"
107+ var fallbackAccent: Color = .gray
108+
109+ private static var cache: [String: NSImage] = [:]
110+
111+ static func image(_ id: String) -> NSImage? {
112+ if let hit = cache[id] { return hit }
113+ guard let url = Bundle.module.url(forResource: "logo-\(id)", withExtension: "png",
114+ subdirectory: "Logos"),
115+ let img = NSImage(contentsOf: url) else { return nil }
116+ cache[id] = img
117+ return img
118+ }
119+
120+ var body: some View {
121+ if let img = Self.image(id) {
122+ Image(nsImage: img)
123+ .resizable()
124+ .interpolation(.high)
125+ .aspectRatio(contentMode: .fit)
126+ .frame(width: size, height: size)
127+ .clipShape(RoundedRectangle(cornerRadius: size * 0.22, style: .continuous))
128+ .accessibilityHidden(true)
129+ } else {
130+ Image(systemName: fallbackSymbol)
131+ .font(.system(size: size * 0.6, weight: .semibold))
132+ .foregroundStyle(fallbackAccent)
133+ .frame(width: size, height: size)
134+ .accessibilityHidden(true)
135+ }
136+ }
137+}
138+
98 // MARK: - Puce mono (klabel) 139 // MARK: - Puce mono (klabel)
99 140
100 struct KAChip: View { 141 struct KAChip: View {
modified Sources/KA/Features/HomeView.swift +2 −5
@@ -138,11 +138,8 @@ struct HomeView: View {
138 } label: { 138 } label: {
139 VStack(alignment: .leading, spacing: 9) { 139 VStack(alignment: .leading, spacing: 9) {
140 HStack { 140 HStack {
141− Image(systemName: u.symbol) 141+ KALogo(id: u.id, size: 38,
142− .font(.title3.weight(.semibold)) 142+ fallbackSymbol: u.symbol, fallbackAccent: u.accent)
143− .foregroundStyle(u.accent)
144− .frame(width: 38, height: 38)
145− .background(u.accent.opacity(0.14), in: RoundedRectangle(cornerRadius: 10, style: .continuous))
146 Spacer() 143 Spacer()
147 Image(systemName: "chevron.right").font(.caption).foregroundStyle(.tertiary) 144 Image(systemName: "chevron.right").font(.caption).foregroundStyle(.tertiary)
148 } 145 }
modified Sources/KA/Features/MainWindow.swift +12 −4
@@ -43,10 +43,8 @@ struct MainWindowView: View {
43 Section("Univers") { 43 Section("Univers") {
44 ForEach(Ecosystem.all) { u in 44 ForEach(Ecosystem.all) { u in
45 HStack(spacing: 8) { 45 HStack(spacing: 8) {
46− Image(systemName: u.symbol) 46+ KALogo(id: u.id, size: 18,
47− .font(.caption.weight(.semibold)) 47+ fallbackSymbol: u.symbol, fallbackAccent: u.accent)
48− .foregroundStyle(u.accent)
49− .frame(width: 18)
50 KAWordmark(universe: u, size: 12) 48 KAWordmark(universe: u, size: 12)
51 Spacer(minLength: 4) 49 Spacer(minLength: 4)
52 if let n = pulse.totals[u.id] { 50 if let n = pulse.totals[u.id] {
@@ -58,6 +56,13 @@ struct MainWindowView: View {
58 } 56 }
59 .tag(SidebarSelection.universe(u.id)) 57 .tag(SidebarSelection.universe(u.id))
60 } 58 }
59+ HStack(spacing: 8) {
60+ KALogo(id: "groupe-ka", size: 18)
61+ Text("groupe-ka.com")
62+ .font(.system(size: 12, weight: .bold, design: .rounded))
63+ }
64+ .tag(SidebarSelection.hub)
65+ .help("Le hub Groupe KA — le site, intégré dans l'app")
61 } 66 }
62 67
63 Section("Bibliothèque") { 68 Section("Bibliothèque") {
@@ -113,6 +118,9 @@ struct MainWindowView: View {
113 case .favorites: FavoritesView() 118 case .favorites: FavoritesView()
114 case .history: HistoryView() 119 case .history: HistoryView()
115 case .alerts: AlertsView() 120 case .alerts: AlertsView()
121+ case .hub:
122+ SiteView(url: Ecosystem.hubURL, title: "Groupe KA",
123+ accent: KATheme.green, logoID: "groupe-ka")
116 case .universe(let id): 124 case .universe(let id):
117 if let u = Ecosystem.universe(id) { 125 if let u = Ecosystem.universe(id) {
118 UniverseExplorerView(universe: u) 126 UniverseExplorerView(universe: u)
modified Sources/KA/Features/MenuBarView.swift +2 −4
@@ -73,10 +73,8 @@ struct MenuBarView: View {
73 focusMainWindow(openWindow) 73 focusMainWindow(openWindow)
74 } label: { 74 } label: {
75 HStack(spacing: 6) { 75 HStack(spacing: 6) {
76− Image(systemName: u.symbol) 76+ KALogo(id: u.id, size: 14,
77− .font(.caption2.weight(.semibold)) 77+ fallbackSymbol: u.symbol, fallbackAccent: u.accent)
78− .foregroundStyle(u.accent)
79− .frame(width: 14)
80 KAWordmark(universe: u, size: 10) 78 KAWordmark(universe: u, size: 10)
81 Spacer(minLength: 2) 79 Spacer(minLength: 2)
82 Text(pulse.totals[u.id].map { Double($0).compact } ?? "—") 80 Text(pulse.totals[u.id].map { Double($0).compact } ?? "—")
added Sources/KA/Features/SiteView.swift +184 −0
@@ -0,0 +1,184 @@
1+// Auteur : Simon-Pierre Boucher — contact@spboucher.ai
2+// SiteView.swift — le SITE WEB d'une plateforme Ka, intégré dans l'app :
3+// WKWebView plein volet avec chrome minimal (retour/avancer, recharger,
4+// domaine courant, partager, ouvrir dans le navigateur) et barre de
5+// progression teintée à l'accent de l'univers. Les liens externes non
6+// web (tel:, mailto:…) partent vers le système.
7+import SwiftUI
8+import WebKit
9+
10+// MARK: - Modèle observable du WKWebView (progression, historique, titre)
11+
12+@MainActor
13+final class SiteWebModel: NSObject, ObservableObject, WKNavigationDelegate, WKUIDelegate {
14+ let webView: WKWebView
15+ @Published var progress: Double = 0
16+ @Published var isLoading = false
17+ @Published var canGoBack = false
18+ @Published var canGoForward = false
19+ @Published var currentURL: URL?
20+
21+ private var observers: [NSKeyValueObservation] = []
22+
23+ init(url: URL) {
24+ let config = WKWebViewConfiguration()
25+ config.defaultWebpagePreferences.allowsContentJavaScript = true
26+ webView = WKWebView(frame: .zero, configuration: config)
27+ webView.allowsBackForwardNavigationGestures = true
28+ webView.allowsMagnification = true
29+ super.init()
30+ webView.navigationDelegate = self
31+ webView.uiDelegate = self
32+ observers = [
33+ webView.observe(\.estimatedProgress) { [weak self] wv, _ in
34+ Task { @MainActor in self?.progress = wv.estimatedProgress }
35+ },
36+ webView.observe(\.isLoading) { [weak self] wv, _ in
37+ Task { @MainActor in self?.isLoading = wv.isLoading }
38+ },
39+ webView.observe(\.canGoBack) { [weak self] wv, _ in
40+ Task { @MainActor in self?.canGoBack = wv.canGoBack }
41+ },
42+ webView.observe(\.canGoForward) { [weak self] wv, _ in
43+ Task { @MainActor in self?.canGoForward = wv.canGoForward }
44+ },
45+ webView.observe(\.url) { [weak self] wv, _ in
46+ Task { @MainActor in self?.currentURL = wv.url }
47+ },
48+ ]
49+ currentURL = url
50+ webView.load(URLRequest(url: url))
51+ }
52+
53+ // Les schémas non web (tel:, mailto:, facetime:…) partent vers le système.
54+ nonisolated func webView(_ webView: WKWebView,
55+ decidePolicyFor navigationAction: WKNavigationAction,
56+ decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
57+ guard let url = navigationAction.request.url else { return decisionHandler(.allow) }
58+ if let scheme = url.scheme?.lowercased(), scheme != "http", scheme != "https", scheme != "about" {
59+ NSWorkspace.shared.open(url)
60+ return decisionHandler(.cancel)
61+ }
62+ decisionHandler(.allow)
63+ }
64+
65+ // target="_blank" : on reste dans la même vue plutôt que d'ouvrir une fenêtre.
66+ nonisolated func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration,
67+ for navigationAction: WKNavigationAction,
68+ windowFeatures: WKWindowFeatures) -> WKWebView? {
69+ if let url = navigationAction.request.url {
70+ Task { @MainActor in webView.load(URLRequest(url: url)) }
71+ }
72+ return nil
73+ }
74+}
75+
76+private struct SiteWebViewRepresentable: NSViewRepresentable {
77+ let model: SiteWebModel
78+ func makeNSView(context: Context) -> WKWebView { model.webView }
79+ func updateNSView(_ nsView: WKWebView, context: Context) {}
80+}
81+
82+// MARK: - Le navigateur intégré (chrome + progression + web)
83+
84+struct SiteView: View {
85+ let url: URL
86+ var title: String
87+ var accent: Color
88+ var logoID: String?
89+ @StateObject private var model: SiteWebModel
90+ @Environment(\.colorScheme) private var scheme
91+
92+ init(url: URL, title: String, accent: Color, logoID: String? = nil) {
93+ self.url = url
94+ self.title = title
95+ self.accent = accent
96+ self.logoID = logoID
97+ _model = StateObject(wrappedValue: SiteWebModel(url: url))
98+ }
99+
100+ init(universe: Universe) {
101+ self.init(url: universe.baseURL, title: universe.name,
102+ accent: universe.accent, logoID: universe.id)
103+ }
104+
105+ var body: some View {
106+ VStack(spacing: 0) {
107+ chrome
108+ ZStack(alignment: .top) {
109+ SiteWebViewRepresentable(model: model)
110+ if model.isLoading {
111+ GeometryReader { geo in
112+ Rectangle()
113+ .fill(accent)
114+ .frame(width: geo.size.width * max(model.progress, 0.06), height: 2.5)
115+ .animation(.easeOut(duration: 0.25), value: model.progress)
116+ }
117+ .frame(height: 2.5)
118+ .accessibilityHidden(true)
119+ }
120+ }
121+ }
122+ .background(KATheme.paper(scheme))
123+ }
124+
125+ private var chrome: some View {
126+ HStack(spacing: 10) {
127+ if let logoID {
128+ KALogo(id: logoID, size: 20, fallbackAccent: accent)
129+ }
130+ Button { model.webView.goBack() } label: {
131+ Image(systemName: "chevron.left")
132+ }
133+ .buttonStyle(.plain)
134+ .disabled(!model.canGoBack)
135+ .help("Page précédente")
136+ Button { model.webView.goForward() } label: {
137+ Image(systemName: "chevron.right")
138+ }
139+ .buttonStyle(.plain)
140+ .disabled(!model.canGoForward)
141+ .help("Page suivante")
142+ Button {
143+ if model.isLoading { model.webView.stopLoading() }
144+ else { model.webView.reload() }
145+ } label: {
146+ Image(systemName: model.isLoading ? "xmark" : "arrow.clockwise")
147+ }
148+ .buttonStyle(.plain)
149+ .help(model.isLoading ? "Arrêter" : "Recharger")
150+
151+ // Domaine courant, façon champ d'adresse (lecture seule)
152+ HStack(spacing: 6) {
153+ Image(systemName: "lock.fill").font(.caption2).foregroundStyle(.secondary)
154+ Text(model.currentURL?.host() ?? url.host() ?? "")
155+ .font(.system(.caption, design: .monospaced).weight(.semibold))
156+ .lineLimit(1)
157+ .truncationMode(.middle)
158+ }
159+ .padding(.horizontal, 10).padding(.vertical, 5)
160+ .frame(maxWidth: .infinity)
161+ .background(KATheme.surface(scheme), in: Capsule())
162+ .overlay(Capsule().strokeBorder(KATheme.ink(scheme).opacity(0.35), lineWidth: 1))
163+ .accessibilityLabel("Adresse : \(model.currentURL?.absoluteString ?? url.absoluteString)")
164+
165+ if let current = model.currentURL {
166+ ShareLink(item: current, subject: Text(title)) {
167+ Image(systemName: "square.and.arrow.up")
168+ }
169+ .buttonStyle(.plain)
170+ .help("Partager la page")
171+ }
172+ Button {
173+ NSWorkspace.shared.open(model.currentURL ?? url)
174+ } label: {
175+ Image(systemName: "safari")
176+ }
177+ .buttonStyle(.plain)
178+ .help("Ouvrir dans le navigateur")
179+ }
180+ .font(.body)
181+ .padding(.horizontal, 12).padding(.vertical, 8)
182+ .background(KATheme.paper(scheme))
183+ }
184+}
modified Sources/KA/Features/UniverseExplorerView.swift +33 −27
@@ -22,44 +22,45 @@ struct UniverseExplorerView: View {
22 @State private var errorText: String? 22 @State private var errorText: String?
23 @State private var asGrid = true 23 @State private var asGrid = true
24 @State private var savedFlash = false 24 @State private var savedFlash = false
25+ /// Bascule Données (explorateur natif) | Site (le vrai site web, intégré).
26+ enum Mode: String, CaseIterable { case donnees = "Données", site = "Site" }
27+ @State private var mode: Mode
28+
29+ init(universe: Universe) {
30+ self.universe = universe
31+ // Les univers sans liste native s'ouvrent directement sur leur site.
32+ let nativeless = universe.listPath == nil || universe.map == nil
33+ let hasCustom = universe.id == "vrai-prix" || universe.id == "api-ka"
34+ _mode = State(initialValue: nativeless && !hasCustom ? .site : .donnees)
35+ }
25 36
26 var body: some View { 37 var body: some View {
27 Group { 38 Group {
28− if universe.id == "vrai-prix" { 39+ if mode == .site {
40+ SiteView(universe: universe)
41+ } else if universe.id == "vrai-prix" {
29 VraiPrixExplorer(universe: universe) 42 VraiPrixExplorer(universe: universe)
30 } else if universe.id == "api-ka" { 43 } else if universe.id == "api-ka" {
31 ApiPlaygroundView(universe: universe) 44 ApiPlaygroundView(universe: universe)
32 } else if universe.listPath == nil || universe.map == nil { 45 } else if universe.listPath == nil || universe.map == nil {
33− webUniverse 46+ SiteView(universe: universe)
34 } else { 47 } else {
35 explorer 48 explorer
36 } 49 }
37 } 50 }
38− } 51+ .toolbar {
39− 52+ ToolbarItem(placement: .principal) {
40− // MARK: univers sans liste native → renvoi au site 53+ Picker("Présentation de \(universe.name)", selection: $mode) {
41− 54+ ForEach(Mode.allCases, id: \.self) { m in
42− private var webUniverse: some View { 55+ Text(m.rawValue).tag(m)
43− VStack(spacing: 18) { 56+ }
44− Image(systemName: universe.symbol).font(.system(size: 52)).foregroundStyle(universe.accent) 57+ }
45− KAWordmark(universe: universe, size: 30) 58+ .pickerStyle(.segmented)
46− Text(universe.tagline).font(.title3).foregroundStyle(.secondary) 59+ .labelsHidden()
47− .multilineTextAlignment(.center) 60+ .frame(width: 170)
48− if let n = pulse.totals[universe.id] { 61+ .help("Données = explorateur natif ; Site = le site web \(universe.domain), intégré")
49− Text("\(n.fr) \(universe.unit)")
50− .font(.system(.subheadline, design: .monospaced).weight(.bold))
51− .foregroundStyle(universe.accent)
52− }
53− Link(destination: universe.baseURL) {
54− Label("Ouvrir \(universe.name)", systemImage: "arrow.up.right.square")
55− .font(.headline).padding(.horizontal, 22).padding(.vertical, 12)
56− .background(universe.accent, in: Capsule())
57− .foregroundStyle(.white)
58 } 62 }
59− .buttonStyle(.plain)
60 } 63 }
61− .padding(30)
62− .frame(maxWidth: .infinity, maxHeight: .infinity)
63 } 64 }
64 65
65 // MARK: explorateur grille/liste + fiche 66 // MARK: explorateur grille/liste + fiche
@@ -101,6 +102,9 @@ struct UniverseExplorerView: View {
101 private var hero: some View { 102 private var hero: some View {
102 VStack(alignment: .leading, spacing: 10) { 103 VStack(alignment: .leading, spacing: 10) {
103 HStack(alignment: .firstTextBaseline, spacing: 12) { 104 HStack(alignment: .firstTextBaseline, spacing: 12) {
105+ KALogo(id: universe.id, size: 26,
106+ fallbackSymbol: universe.symbol, fallbackAccent: universe.accent)
107+ .alignmentGuide(.firstTextBaseline) { $0[VerticalAlignment.center] + 8 }
104 KAWordmark(universe: universe, size: 24) 108 KAWordmark(universe: universe, size: 24)
105 Text(universe.tagline) 109 Text(universe.tagline)
106 .font(.system(.subheadline, design: .rounded).weight(.bold)) 110 .font(.system(.subheadline, design: .rounded).weight(.bold))
@@ -121,11 +125,13 @@ struct UniverseExplorerView: View {
121 .pickerStyle(.segmented) 125 .pickerStyle(.segmented)
122 .labelsHidden() 126 .labelsHidden()
123 .frame(width: 90) 127 .frame(width: 90)
124− Link(destination: universe.baseURL) { 128+ Button { mode = .site } label: {
125− Label("Ouvrir le site", systemImage: "safari") 129+ Label("Voir le site", systemImage: "safari")
126 .font(.caption.weight(.semibold)) 130 .font(.caption.weight(.semibold))
127 } 131 }
132+ .buttonStyle(.plain)
128 .foregroundStyle(universe.accent) 133 .foregroundStyle(universe.accent)
134+ .help("Ouvrir \(universe.domain) dans l'app")
129 } 135 }
130 HStack(spacing: 8) { 136 HStack(spacing: 8) {
131 KASearchField(prompt: "Chercher dans \(universe.name)…", text: $query) { 137 KASearchField(prompt: "Chercher dans \(universe.name)…", text: $query) {
added Sources/KA/Resources/Logos/logo-api-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-auto-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-crea-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-fabri-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-food-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-groupe-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-immo-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-job-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-lou-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-resto-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-sorti-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-trouve-ka.png +0 −0

Binary file not shown.

added Sources/KA/Resources/Logos/logo-vrai-prix.png +0 −0

Binary file not shown.

modified scripts/notarize.sh +1 −1
@@ -9,7 +9,7 @@ cd "$(dirname "$0")/.."
9 IDENTITY="Developer ID Application: Simon-Pierre Boucher (3YM54G49SN)" 9 IDENTITY="Developer ID Application: Simon-Pierre Boucher (3YM54G49SN)"
10 KEYCHAIN_PROFILE="MacLustr-Notarize" 10 KEYCHAIN_PROFILE="MacLustr-Notarize"
11 APP_DIR="dist/KA.app" 11 APP_DIR="dist/KA.app"
12−DMG_NAME="dist/KA-macos-1.0.0.dmg" # publié en téléchargement sur groupe-ka.com 12+DMG_NAME="dist/KA-macos-2.0.0.dmg" # publié en téléchargement sur groupe-ka.com
13 13
14 ./scripts/package-app.sh release 14 ./scripts/package-app.sh release
15 15
modified scripts/package-app.sh +4 −2
@@ -17,6 +17,8 @@ mkdir -p "$APP_DIR/Contents/MacOS" "$APP_DIR/Contents/Resources"
17 cp "$BIN" "$APP_DIR/Contents/MacOS/KA" 17 cp "$BIN" "$APP_DIR/Contents/MacOS/KA"
18 if [ ! -f Assets/AppIcon.icns ]; then ./scripts/generate-icon.sh; fi 18 if [ ! -f Assets/AppIcon.icns ]; then ./scripts/generate-icon.sh; fi
19 cp Assets/AppIcon.icns "$APP_DIR/Contents/Resources/AppIcon.icns" 19 cp Assets/AppIcon.icns "$APP_DIR/Contents/Resources/AppIcon.icns"
20+# Bundle de ressources SwiftPM (logos des 13 marques) — requis par Bundle.module
21+cp -R ".build/$CONFIG/KA_KA.bundle" "$APP_DIR/Contents/Resources/"
20 22
21 cat > "$APP_DIR/Contents/Info.plist" <<'PLIST' 23 cat > "$APP_DIR/Contents/Info.plist" <<'PLIST'
22 <?xml version="1.0" encoding="UTF-8"?> 24 <?xml version="1.0" encoding="UTF-8"?>
@@ -27,8 +29,8 @@ cat > "$APP_DIR/Contents/Info.plist" <<'PLIST'
27 <key>CFBundleDisplayName</key><string>KA</string> 29 <key>CFBundleDisplayName</key><string>KA</string>
28 <key>CFBundleIdentifier</key><string>com.groupeka.ka.mac</string> 30 <key>CFBundleIdentifier</key><string>com.groupeka.ka.mac</string>
29 <key>CFBundleExecutable</key><string>KA</string> 31 <key>CFBundleExecutable</key><string>KA</string>
30− <key>CFBundleVersion</key><string>1</string> 32+ <key>CFBundleVersion</key><string>2</string>
31− <key>CFBundleShortVersionString</key><string>1.0.0</string> 33+ <key>CFBundleShortVersionString</key><string>2.0.0</string>
32 <key>CFBundlePackageType</key><string>APPL</string> 34 <key>CFBundlePackageType</key><string>APPL</string>
33 <key>LSMinimumSystemVersion</key><string>14.0</string> 35 <key>LSMinimumSystemVersion</key><string>14.0</string>
34 <key>LSApplicationCategoryType</key><string>public.app-category.lifestyle</string> 36 <key>LSApplicationCategoryType</key><string>public.app-category.lifestyle</string>
35 37
Menu

Theme