SPB Git forge
2commits 1branches 0releases
180.0 KBsize
maindefault branch
1 mo agolast push
Swift 100%

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 1 mo ago (Aug 21, 2026)

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