SPB Git

Admin-Ka macOS 1.0.0 — app native SwiftUI (WKWebView) notarisée, identité Ka

- shell SwiftUI natif macOS enveloppant administration-ka.com (cookie persistant, liens externes → navigateur, panneaux JS natifs pour confirm/bypass)
- icône + splash pastille Ka, fenêtre redimensionnable, hardened runtime
- signé Developer ID Application + notarisé (notarytool via clé API ASC) + stapled + DMG

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

19 changed files +659 −0

added .gitignore +7 −0
@@ -0,0 +1,7 @@
1+.DS_Store
2+build/
3+DerivedData/
4+dist/
5+*.xcuserstate
6+xcuserdata/
7+screenshots/
added AdminKaMac.xcodeproj/project.pbxproj +339 −0
@@ -0,0 +1,339 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 77;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 82BA6DA43D75AB5CDF765360 /* AdminKaMacApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1BE00C7998B3AE9281938C8 /* AdminKaMacApp.swift */; };
11+ A2299018D551DE323C453439 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 02C21000306216EFA864AC79 /* Assets.xcassets */; };
12+ AA4AB8779667D82483FAF045 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A456697E2205919C39C44B /* RootView.swift */; };
13+ AE613712E51ECADC4D983C00 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7EA81E05D09A3B32940539 /* Theme.swift */; };
14+ E574FBC46EA6ED96B8196E1C /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C8E8B6E60526309BC2B9243 /* WebView.swift */; };
15+/* End PBXBuildFile section */
16+
17+/* Begin PBXFileReference section */
18+ 02C21000306216EFA864AC79 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
19+ 5D4FBD2391C5AA22EC0D3742 /* AdminKaMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AdminKaMac.app; sourceTree = BUILT_PRODUCTS_DIR; };
20+ 5E7EA81E05D09A3B32940539 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
21+ 8C8E8B6E60526309BC2B9243 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = "<group>"; };
22+ B00B669430E6EA7BF4185289 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
23+ B1BE00C7998B3AE9281938C8 /* AdminKaMacApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminKaMacApp.swift; sourceTree = "<group>"; };
24+ CA0F4A21CCC1477D4A5A60A6 /* AdminKaMac.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AdminKaMac.entitlements; sourceTree = "<group>"; };
25+ E6A456697E2205919C39C44B /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
26+/* End PBXFileReference section */
27+
28+/* Begin PBXGroup section */
29+ 250ED03615C8C0848BF90A43 /* Products */ = {
30+ isa = PBXGroup;
31+ children = (
32+ 5D4FBD2391C5AA22EC0D3742 /* AdminKaMac.app */,
33+ );
34+ name = Products;
35+ sourceTree = "<group>";
36+ };
37+ 7A72F9E8B22A3A6F48B7CA35 /* Sources */ = {
38+ isa = PBXGroup;
39+ children = (
40+ CA0F4A21CCC1477D4A5A60A6 /* AdminKaMac.entitlements */,
41+ B1BE00C7998B3AE9281938C8 /* AdminKaMacApp.swift */,
42+ B00B669430E6EA7BF4185289 /* Info.plist */,
43+ E6A456697E2205919C39C44B /* RootView.swift */,
44+ 5E7EA81E05D09A3B32940539 /* Theme.swift */,
45+ 8C8E8B6E60526309BC2B9243 /* WebView.swift */,
46+ );
47+ path = Sources;
48+ sourceTree = "<group>";
49+ };
50+ B39C7C2CA1E0D8B5F2EAB354 = {
51+ isa = PBXGroup;
52+ children = (
53+ E5ABD6EDCFF9EC4DE2BF91C6 /* Resources */,
54+ 7A72F9E8B22A3A6F48B7CA35 /* Sources */,
55+ 250ED03615C8C0848BF90A43 /* Products */,
56+ );
57+ sourceTree = "<group>";
58+ };
59+ E5ABD6EDCFF9EC4DE2BF91C6 /* Resources */ = {
60+ isa = PBXGroup;
61+ children = (
62+ 02C21000306216EFA864AC79 /* Assets.xcassets */,
63+ );
64+ path = Resources;
65+ sourceTree = "<group>";
66+ };
67+/* End PBXGroup section */
68+
69+/* Begin PBXNativeTarget section */
70+ F9853118CD34A10A9B8E4F90 /* AdminKaMac */ = {
71+ isa = PBXNativeTarget;
72+ buildConfigurationList = 37792F69F119471FA311BAB8 /* Build configuration list for PBXNativeTarget "AdminKaMac" */;
73+ buildPhases = (
74+ 7008F5E82F8952C5A7C036B7 /* Sources */,
75+ C2FB09DFDC9F286E4B1ECB79 /* Resources */,
76+ );
77+ buildRules = (
78+ );
79+ dependencies = (
80+ );
81+ name = AdminKaMac;
82+ packageProductDependencies = (
83+ );
84+ productName = AdminKaMac;
85+ productReference = 5D4FBD2391C5AA22EC0D3742 /* AdminKaMac.app */;
86+ productType = "com.apple.product-type.application";
87+ };
88+/* End PBXNativeTarget section */
89+
90+/* Begin PBXProject section */
91+ FB566ECDA392935EE6C8E20F /* Project object */ = {
92+ isa = PBXProject;
93+ attributes = {
94+ BuildIndependentTargetsInParallel = YES;
95+ LastUpgradeCheck = 1430;
96+ TargetAttributes = {
97+ F9853118CD34A10A9B8E4F90 = {
98+ DevelopmentTeam = 3YM54G49SN;
99+ ProvisioningStyle = Manual;
100+ };
101+ };
102+ };
103+ buildConfigurationList = A6EFFDB2CC27831A956303CB /* Build configuration list for PBXProject "AdminKaMac" */;
104+ developmentRegion = en;
105+ hasScannedForEncodings = 0;
106+ knownRegions = (
107+ Base,
108+ en,
109+ );
110+ mainGroup = B39C7C2CA1E0D8B5F2EAB354;
111+ minimizedProjectReferenceProxies = 1;
112+ preferredProjectObjectVersion = 77;
113+ productRefGroup = 250ED03615C8C0848BF90A43 /* Products */;
114+ projectDirPath = "";
115+ projectRoot = "";
116+ targets = (
117+ F9853118CD34A10A9B8E4F90 /* AdminKaMac */,
118+ );
119+ };
120+/* End PBXProject section */
121+
122+/* Begin PBXResourcesBuildPhase section */
123+ C2FB09DFDC9F286E4B1ECB79 /* Resources */ = {
124+ isa = PBXResourcesBuildPhase;
125+ buildActionMask = 2147483647;
126+ files = (
127+ A2299018D551DE323C453439 /* Assets.xcassets in Resources */,
128+ );
129+ runOnlyForDeploymentPostprocessing = 0;
130+ };
131+/* End PBXResourcesBuildPhase section */
132+
133+/* Begin PBXSourcesBuildPhase section */
134+ 7008F5E82F8952C5A7C036B7 /* Sources */ = {
135+ isa = PBXSourcesBuildPhase;
136+ buildActionMask = 2147483647;
137+ files = (
138+ 82BA6DA43D75AB5CDF765360 /* AdminKaMacApp.swift in Sources */,
139+ AA4AB8779667D82483FAF045 /* RootView.swift in Sources */,
140+ AE613712E51ECADC4D983C00 /* Theme.swift in Sources */,
141+ E574FBC46EA6ED96B8196E1C /* WebView.swift in Sources */,
142+ );
143+ runOnlyForDeploymentPostprocessing = 0;
144+ };
145+/* End PBXSourcesBuildPhase section */
146+
147+/* Begin XCBuildConfiguration section */
148+ 47C2705EB0F5CFC9CED0406F /* Release */ = {
149+ isa = XCBuildConfiguration;
150+ buildSettings = {
151+ ALWAYS_SEARCH_USER_PATHS = NO;
152+ CLANG_ANALYZER_NONNULL = YES;
153+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
154+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
155+ CLANG_CXX_LIBRARY = "libc++";
156+ CLANG_ENABLE_MODULES = YES;
157+ CLANG_ENABLE_OBJC_ARC = YES;
158+ CLANG_ENABLE_OBJC_WEAK = YES;
159+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
160+ CLANG_WARN_BOOL_CONVERSION = YES;
161+ CLANG_WARN_COMMA = YES;
162+ CLANG_WARN_CONSTANT_CONVERSION = YES;
163+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
164+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
165+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
166+ CLANG_WARN_EMPTY_BODY = YES;
167+ CLANG_WARN_ENUM_CONVERSION = YES;
168+ CLANG_WARN_INFINITE_RECURSION = YES;
169+ CLANG_WARN_INT_CONVERSION = YES;
170+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
171+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
172+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
173+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
174+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
175+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
176+ CLANG_WARN_STRICT_PROTOTYPES = YES;
177+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
178+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
179+ CLANG_WARN_UNREACHABLE_CODE = YES;
180+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
181+ COPY_PHASE_STRIP = NO;
182+ CURRENT_PROJECT_VERSION = 1;
183+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
184+ DEVELOPMENT_TEAM = 3YM54G49SN;
185+ ENABLE_NS_ASSERTIONS = NO;
186+ ENABLE_STRICT_OBJC_MSGSEND = YES;
187+ GCC_C_LANGUAGE_STANDARD = gnu11;
188+ GCC_NO_COMMON_BLOCKS = YES;
189+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
190+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
191+ GCC_WARN_UNDECLARED_SELECTOR = YES;
192+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
193+ GCC_WARN_UNUSED_FUNCTION = YES;
194+ GCC_WARN_UNUSED_VARIABLE = YES;
195+ MACOSX_DEPLOYMENT_TARGET = 13.0;
196+ MARKETING_VERSION = 1.0.0;
197+ MTL_ENABLE_DEBUG_INFO = NO;
198+ MTL_FAST_MATH = YES;
199+ PRODUCT_NAME = "$(TARGET_NAME)";
200+ SDKROOT = macosx;
201+ SWIFT_COMPILATION_MODE = wholemodule;
202+ SWIFT_OPTIMIZATION_LEVEL = "-O";
203+ SWIFT_VERSION = 5.0;
204+ };
205+ name = Release;
206+ };
207+ 9F641E359B9E74716ED4B9E5 /* Release */ = {
208+ isa = XCBuildConfiguration;
209+ buildSettings = {
210+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
211+ CODE_SIGN_ENTITLEMENTS = Sources/AdminKaMac.entitlements;
212+ CODE_SIGN_IDENTITY = "Developer ID Application";
213+ CODE_SIGN_STYLE = Manual;
214+ COMBINE_HIDPI_IMAGES = YES;
215+ ENABLE_HARDENED_RUNTIME = YES;
216+ INFOPLIST_FILE = Sources/Info.plist;
217+ LD_RUNPATH_SEARCH_PATHS = (
218+ "$(inherited)",
219+ "@executable_path/../Frameworks",
220+ );
221+ MACOSX_DEPLOYMENT_TARGET = 13.0;
222+ PRODUCT_BUNDLE_IDENTIFIER = com.groupeka.adminkamac;
223+ PRODUCT_NAME = "Admin-Ka";
224+ SDKROOT = macosx;
225+ };
226+ name = Release;
227+ };
228+ CA399800D52E645C7E657403 /* Debug */ = {
229+ isa = XCBuildConfiguration;
230+ buildSettings = {
231+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
232+ CODE_SIGN_ENTITLEMENTS = Sources/AdminKaMac.entitlements;
233+ CODE_SIGN_IDENTITY = "Developer ID Application";
234+ CODE_SIGN_STYLE = Manual;
235+ COMBINE_HIDPI_IMAGES = YES;
236+ ENABLE_HARDENED_RUNTIME = YES;
237+ INFOPLIST_FILE = Sources/Info.plist;
238+ LD_RUNPATH_SEARCH_PATHS = (
239+ "$(inherited)",
240+ "@executable_path/../Frameworks",
241+ );
242+ MACOSX_DEPLOYMENT_TARGET = 13.0;
243+ PRODUCT_BUNDLE_IDENTIFIER = com.groupeka.adminkamac;
244+ PRODUCT_NAME = "Admin-Ka";
245+ SDKROOT = macosx;
246+ };
247+ name = Debug;
248+ };
249+ E5F59090737C7E513CCF4FB1 /* Debug */ = {
250+ isa = XCBuildConfiguration;
251+ buildSettings = {
252+ ALWAYS_SEARCH_USER_PATHS = NO;
253+ CLANG_ANALYZER_NONNULL = YES;
254+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
255+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
256+ CLANG_CXX_LIBRARY = "libc++";
257+ CLANG_ENABLE_MODULES = YES;
258+ CLANG_ENABLE_OBJC_ARC = YES;
259+ CLANG_ENABLE_OBJC_WEAK = YES;
260+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
261+ CLANG_WARN_BOOL_CONVERSION = YES;
262+ CLANG_WARN_COMMA = YES;
263+ CLANG_WARN_CONSTANT_CONVERSION = YES;
264+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
265+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
266+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
267+ CLANG_WARN_EMPTY_BODY = YES;
268+ CLANG_WARN_ENUM_CONVERSION = YES;
269+ CLANG_WARN_INFINITE_RECURSION = YES;
270+ CLANG_WARN_INT_CONVERSION = YES;
271+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
272+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
273+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
274+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
275+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
276+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
277+ CLANG_WARN_STRICT_PROTOTYPES = YES;
278+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
279+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
280+ CLANG_WARN_UNREACHABLE_CODE = YES;
281+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
282+ COPY_PHASE_STRIP = NO;
283+ CURRENT_PROJECT_VERSION = 1;
284+ DEBUG_INFORMATION_FORMAT = dwarf;
285+ DEVELOPMENT_TEAM = 3YM54G49SN;
286+ ENABLE_STRICT_OBJC_MSGSEND = YES;
287+ ENABLE_TESTABILITY = YES;
288+ GCC_C_LANGUAGE_STANDARD = gnu11;
289+ GCC_DYNAMIC_NO_PIC = NO;
290+ GCC_NO_COMMON_BLOCKS = YES;
291+ GCC_OPTIMIZATION_LEVEL = 0;
292+ GCC_PREPROCESSOR_DEFINITIONS = (
293+ "$(inherited)",
294+ "DEBUG=1",
295+ );
296+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
297+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
298+ GCC_WARN_UNDECLARED_SELECTOR = YES;
299+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
300+ GCC_WARN_UNUSED_FUNCTION = YES;
301+ GCC_WARN_UNUSED_VARIABLE = YES;
302+ MACOSX_DEPLOYMENT_TARGET = 13.0;
303+ MARKETING_VERSION = 1.0.0;
304+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
305+ MTL_FAST_MATH = YES;
306+ ONLY_ACTIVE_ARCH = YES;
307+ PRODUCT_NAME = "$(TARGET_NAME)";
308+ SDKROOT = macosx;
309+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
310+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
311+ SWIFT_VERSION = 5.0;
312+ };
313+ name = Debug;
314+ };
315+/* End XCBuildConfiguration section */
316+
317+/* Begin XCConfigurationList section */
318+ 37792F69F119471FA311BAB8 /* Build configuration list for PBXNativeTarget "AdminKaMac" */ = {
319+ isa = XCConfigurationList;
320+ buildConfigurations = (
321+ CA399800D52E645C7E657403 /* Debug */,
322+ 9F641E359B9E74716ED4B9E5 /* Release */,
323+ );
324+ defaultConfigurationIsVisible = 0;
325+ defaultConfigurationName = Debug;
326+ };
327+ A6EFFDB2CC27831A956303CB /* Build configuration list for PBXProject "AdminKaMac" */ = {
328+ isa = XCConfigurationList;
329+ buildConfigurations = (
330+ E5F59090737C7E513CCF4FB1 /* Debug */,
331+ 47C2705EB0F5CFC9CED0406F /* Release */,
332+ );
333+ defaultConfigurationIsVisible = 0;
334+ defaultConfigurationName = Debug;
335+ };
336+/* End XCConfigurationList section */
337+ };
338+ rootObject = FB566ECDA392935EE6C8E20F /* Project object */;
339+}
added AdminKaMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 −0
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:">
6+ </FileRef>
7+</Workspace>
added Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +15 −0
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {"idiom":"mac","scale":"1x","size":"16x16","filename":"icon_16.png"},
4+ {"idiom":"mac","scale":"2x","size":"16x16","filename":"icon_32.png"},
5+ {"idiom":"mac","scale":"1x","size":"32x32","filename":"icon_32.png"},
6+ {"idiom":"mac","scale":"2x","size":"32x32","filename":"icon_64.png"},
7+ {"idiom":"mac","scale":"1x","size":"128x128","filename":"icon_128.png"},
8+ {"idiom":"mac","scale":"2x","size":"128x128","filename":"icon_256.png"},
9+ {"idiom":"mac","scale":"1x","size":"256x256","filename":"icon_256.png"},
10+ {"idiom":"mac","scale":"2x","size":"256x256","filename":"icon_512.png"},
11+ {"idiom":"mac","scale":"1x","size":"512x512","filename":"icon_512.png"},
12+ {"idiom":"mac","scale":"2x","size":"512x512","filename":"icon_1024.png"}
13+ ],
14+ "info" : { "author" : "xcode", "version" : 1 }
15+}
added Resources/Assets.xcassets/AppIcon.appiconset/icon_1024.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/AppIcon.appiconset/icon_128.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/AppIcon.appiconset/icon_16.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/AppIcon.appiconset/icon_256.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/AppIcon.appiconset/icon_32.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/AppIcon.appiconset/icon_512.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/AppIcon.appiconset/icon_64.png +0 −0

Binary file not shown.

added Resources/Assets.xcassets/Contents.json +1 −0
@@ -0,0 +1 @@
1+{ "info" : { "author" : "xcode", "version" : 1 } }
added Sources/AdminKaMac.entitlements +6 −0
@@ -0,0 +1,6 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0"><dict>
4+ <key>com.apple.security.app-sandbox</key><false/>
5+ <key>com.apple.security.network.client</key><true/>
6+</dict></plist>
added Sources/AdminKaMacApp.swift +14 −0
@@ -0,0 +1,14 @@
1+import SwiftUI
2+
3+@main
4+struct AdminKaMacApp: App {
5+ var body: some Scene {
6+ WindowGroup {
7+ RootView()
8+ .frame(minWidth: 420, idealWidth: 520, maxWidth: .infinity,
9+ minHeight: 640, idealHeight: 860, maxHeight: .infinity)
10+ }
11+ .windowResizability(.contentSize)
12+ .commands { CommandGroup(replacing: .newItem) {} }
13+ }
14+}
added Sources/Info.plist +33 −0
@@ -0,0 +1,33 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>CFBundleDevelopmentRegion</key>
6+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7+ <key>CFBundleDisplayName</key>
8+ <string>Admin-Ka</string>
9+ <key>CFBundleExecutable</key>
10+ <string>$(EXECUTABLE_NAME)</string>
11+ <key>CFBundleIdentifier</key>
12+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13+ <key>CFBundleInfoDictionaryVersion</key>
14+ <string>6.0</string>
15+ <key>CFBundleName</key>
16+ <string>$(PRODUCT_NAME)</string>
17+ <key>CFBundlePackageType</key>
18+ <string>APPL</string>
19+ <key>CFBundleShortVersionString</key>
20+ <string>1.0.0</string>
21+ <key>CFBundleVersion</key>
22+ <string>1</string>
23+ <key>LSMinimumSystemVersion</key>
24+ <string>13.0</string>
25+ <key>NSAppTransportSecurity</key>
26+ <dict>
27+ <key>NSAllowsArbitraryLoads</key>
28+ <false/>
29+ </dict>
30+ <key>NSHumanReadableCopyright</key>
31+ <string>© 2026 Simon-Pierre Boucher — Groupe KA</string>
32+</dict>
33+</plist>
added Sources/RootView.swift +65 −0
@@ -0,0 +1,65 @@
1+import SwiftUI
2+
3+struct RootView: View {
4+ @StateObject private var model = WebModel()
5+ @State private var showSplash = true
6+
7+ var body: some View {
8+ ZStack {
9+ Ka.bg.ignoresSafeArea()
10+ WebView(model: model).opacity(model.loaded ? 1 : 0)
11+
12+ if !model.loaded && !model.failed {
13+ VStack(spacing: 0) {
14+ GeometryReader { geo in
15+ Rectangle().fill(Ka.orange)
16+ .frame(width: geo.size.width * max(0.04, model.progress), height: 3)
17+ .animation(.easeOut(duration: 0.25), value: model.progress)
18+ }.frame(height: 3)
19+ Spacer()
20+ }
21+ }
22+ if showSplash { splash.transition(.opacity) }
23+ if model.failed { offline }
24+ }
25+ .onChange(of: model.loaded) { loaded in
26+ if loaded {
27+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
28+ withAnimation(.easeInOut(duration: 0.4)) { showSplash = false }
29+ }
30+ }
31+ }
32+ }
33+
34+ private var splash: some View {
35+ ZStack {
36+ Ka.bg.ignoresSafeArea()
37+ VStack(spacing: 16) {
38+ KaMark(size: 88)
39+ Text("Admin-Ka").font(.system(size: 24, weight: .heavy, design: .rounded)).foregroundColor(Ka.ink)
40+ Text("Console Claude Code · Groupe KA")
41+ .font(.system(size: 13, weight: .semibold, design: .rounded)).foregroundColor(Ka.muted)
42+ if !model.failed { ProgressView().controlSize(.small).padding(.top, 4) }
43+ }
44+ }
45+ }
46+
47+ private var offline: some View {
48+ ZStack {
49+ Ka.bg.ignoresSafeArea()
50+ VStack(spacing: 14) {
51+ KaMark(size: 68)
52+ Text("Hors ligne").font(.system(size: 20, weight: .heavy, design: .rounded)).foregroundColor(Ka.ink)
53+ Text("Impossible de joindre administration-ka.com")
54+ .font(.system(size: 13, weight: .medium, design: .rounded)).foregroundColor(Ka.muted)
55+ Button {
56+ showSplash = true; model.reload()
57+ } label: {
58+ Text("Réessayer").font(.system(size: 14, weight: .heavy, design: .rounded))
59+ .foregroundColor(Ka.ink).padding(.horizontal, 22).padding(.vertical, 10)
60+ .background(Capsule().fill(Ka.orange).overlay(Capsule().strokeBorder(Ka.ink, lineWidth: 2)))
61+ }.buttonStyle(.plain).padding(.top, 4)
62+ }
63+ }
64+ }
65+}
added Sources/Theme.swift +34 −0
@@ -0,0 +1,34 @@
1+import SwiftUI
2+
3+enum Ka {
4+ static let bg = Color(hex: 0xF2F1EC)
5+ static let card = Color(hex: 0xFCFBF8)
6+ static let ink = Color(hex: 0x1A1611)
7+ static let orange = Color(hex: 0xF97316)
8+ static let muted = Color(hex: 0x6D675C)
9+ static let url = URL(string: "https://www.administration-ka.com")!
10+}
11+
12+extension Color {
13+ init(hex: UInt, alpha: Double = 1) {
14+ self.init(.sRGB,
15+ red: Double((hex >> 16) & 0xff) / 255,
16+ green: Double((hex >> 8) & 0xff) / 255,
17+ blue: Double(hex & 0xff) / 255,
18+ opacity: alpha)
19+ }
20+}
21+
22+struct KaMark: View {
23+ var size: CGFloat = 84
24+ var body: some View {
25+ RoundedRectangle(cornerRadius: size * 0.28, style: .continuous)
26+ .fill(Ka.orange)
27+ .overlay(RoundedRectangle(cornerRadius: size * 0.28, style: .continuous)
28+ .strokeBorder(Ka.ink, lineWidth: max(2, size * 0.035)))
29+ .overlay(Text("Ka")
30+ .font(.system(size: size * 0.42, weight: .heavy, design: .rounded))
31+ .foregroundColor(Ka.ink))
32+ .frame(width: size, height: size)
33+ }
34+}
added Sources/WebView.swift +98 −0
@@ -0,0 +1,98 @@
1+import SwiftUI
2+import WebKit
3+import AppKit
4+
5+final class WebModel: ObservableObject {
6+ @Published var progress: Double = 0
7+ @Published var loaded = false
8+ @Published var failed = false
9+ var webView: WKWebView?
10+ func reload() {
11+ failed = false; loaded = false; progress = 0
12+ if let wv = webView { if wv.url == nil { wv.load(URLRequest(url: Ka.url)) } else { wv.reload() } }
13+ }
14+}
15+
16+struct WebView: NSViewRepresentable {
17+ @ObservedObject var model: WebModel
18+
19+ func makeCoordinator() -> Coordinator { Coordinator(model: model) }
20+
21+ func makeNSView(context: Context) -> WKWebView {
22+ let cfg = WKWebViewConfiguration()
23+ cfg.websiteDataStore = .default() // cookie de session persistant
24+ cfg.defaultWebpagePreferences.allowsContentJavaScript = true
25+ let wv = WKWebView(frame: .zero, configuration: cfg)
26+ wv.navigationDelegate = context.coordinator
27+ wv.uiDelegate = context.coordinator
28+ wv.setValue(false, forKey: "drawsBackground") // fond transparent → crème
29+ wv.customUserAgent = "AdminKa-macOS/1.0 (Groupe KA console)"
30+ context.coordinator.observe(wv)
31+ model.webView = wv
32+ wv.load(URLRequest(url: Ka.url))
33+ return wv
34+ }
35+
36+ func updateNSView(_ nsView: WKWebView, context: Context) {}
37+
38+ final class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
39+ let model: WebModel
40+ private var obs: NSKeyValueObservation?
41+ init(model: WebModel) { self.model = model }
42+
43+ func observe(_ wv: WKWebView) {
44+ obs = wv.observe(\.estimatedProgress, options: [.new]) { [weak self] wv, _ in
45+ DispatchQueue.main.async { self?.model.progress = wv.estimatedProgress }
46+ }
47+ }
48+ func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
49+ DispatchQueue.main.async {
50+ withAnimation(.easeOut(duration: 0.35)) { self.model.loaded = true }
51+ self.model.failed = false
52+ }
53+ }
54+ func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { fail(error) }
55+ func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { fail(error) }
56+ private func fail(_ error: Error) {
57+ if (error as NSError).code == NSURLErrorCancelled { return }
58+ DispatchQueue.main.async { self.model.failed = true }
59+ }
60+
61+ // liens externes → navigateur par défaut
62+ func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
63+ decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
64+ if let url = navigationAction.request.url, let host = url.host,
65+ navigationAction.navigationType == .linkActivated, host != Ka.url.host {
66+ NSWorkspace.shared.open(url); decisionHandler(.cancel); return
67+ }
68+ decisionHandler(.allow)
69+ }
70+ func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration,
71+ for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
72+ if let url = navigationAction.request.url { NSWorkspace.shared.open(url) }
73+ return nil
74+ }
75+
76+ // --- Panneaux JS natifs (confirm() indispensable pour le mode BYPASS) ---
77+ func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
78+ initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
79+ let a = NSAlert(); a.messageText = "Admin-Ka"; a.informativeText = message; a.addButton(withTitle: "OK")
80+ a.runModal(); completionHandler()
81+ }
82+ func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String,
83+ initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
84+ let a = NSAlert(); a.messageText = "Admin-Ka"; a.informativeText = message
85+ a.addButton(withTitle: "OK"); a.addButton(withTitle: "Annuler")
86+ completionHandler(a.runModal() == .alertFirstButtonReturn)
87+ }
88+ func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String,
89+ defaultText: String?, initiatedByFrame frame: WKFrameInfo,
90+ completionHandler: @escaping (String?) -> Void) {
91+ let a = NSAlert(); a.messageText = "Admin-Ka"; a.informativeText = prompt
92+ a.addButton(withTitle: "OK"); a.addButton(withTitle: "Annuler")
93+ let tf = NSTextField(frame: NSRect(x: 0, y: 0, width: 260, height: 24)); tf.stringValue = defaultText ?? ""
94+ a.accessoryView = tf
95+ completionHandler(a.runModal() == .alertFirstButtonReturn ? tf.stringValue : nil)
96+ }
97+ }
98+}
added project.yml +40 −0
@@ -0,0 +1,40 @@
1+name: AdminKaMac
2+options:
3+ bundleIdPrefix: com.groupeka
4+ deploymentTarget:
5+ macOS: "13.0"
6+ createIntermediateGroups: true
7+settings:
8+ base:
9+ MARKETING_VERSION: "1.0.0"
10+ CURRENT_PROJECT_VERSION: "1"
11+ DEVELOPMENT_TEAM: "3YM54G49SN"
12+ SWIFT_VERSION: "5.0"
13+targets:
14+ AdminKaMac:
15+ type: application
16+ platform: macOS
17+ sources:
18+ - Sources
19+ - Resources
20+ info:
21+ path: Sources/Info.plist
22+ properties:
23+ CFBundleDisplayName: Admin-Ka
24+ CFBundleShortVersionString: "1.0.0"
25+ CFBundleVersion: "1"
26+ LSMinimumSystemVersion: "13.0"
27+ NSHumanReadableCopyright: "© 2026 Simon-Pierre Boucher — Groupe KA"
28+ NSAppTransportSecurity:
29+ NSAllowsArbitraryLoads: false
30+ settings:
31+ base:
32+ PRODUCT_BUNDLE_IDENTIFIER: com.groupeka.adminkamac
33+ PRODUCT_NAME: Admin-Ka
34+ ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
35+ ENABLE_HARDENED_RUNTIME: "YES"
36+ CODE_SIGN_STYLE: Manual
37+ CODE_SIGN_IDENTITY: "Developer ID Application"
38+ COMBINE_HIDPI_IMAGES: "YES"
39+ MACOSX_DEPLOYMENT_TARGET: "13.0"
40+ CODE_SIGN_ENTITLEMENTS: Sources/AdminKaMac.entitlements
41
Menu

Theme