{"id":3172,"date":"2026-04-03T09:34:09","date_gmt":"2026-04-03T08:34:09","guid":{"rendered":"https:\/\/www.kangama.com\/?p=3172"},"modified":"2026-05-07T14:15:43","modified_gmt":"2026-05-07T13:15:43","slug":"menu-bar-macos-swiftui-guide-pratique","status":"publish","type":"post","link":"https:\/\/www.kangama.com\/en\/menu-bar-macos-swiftui-guide-pratique\/","title":{"rendered":"Comment cr\u00e9er une menu bar utile sur macOS avec SwiftUI"},"content":{"rendered":"<div id=\"bsf_rt_marker\"><\/div>\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Apr\u00e8s avoir d\u00e9velopp\u00e9 un outil macOS pour <a href=\"https:\/\/www.kangama.com\/outil-macos-nettoyer-cache-developpeur\/\" data-type=\"post\" data-id=\"3105\"><strong>nettoyer les caches d\u00e9veloppeur<\/strong><\/a>, une question s\u2019est rapidement pos\u00e9e : <br>Comment rendre cet outil accessible en permanence, sans alourdir l\u2019exp\u00e9rience utilisateur ?<\/p>\n\n\n\n<p>Sur macOS, la r\u00e9ponse est souvent \u00e9vidente : <strong>menu bar<\/strong>.<\/p>\n\n\n\n<p>Discr\u00e8te, toujours accessible et parfaitement int\u00e9gr\u00e9e au syst\u00e8me, la menu bar macOS permet de proposer des actions rapides sans passer par une fen\u00eatre classique. Pourtant, sa mise en place avec SwiftUI soul\u00e8ve quelques subtilit\u00e9s, notamment si l\u2019on veut aller au-del\u00e0 d\u2019un simple menu statique.<\/p>\n\n\n\n<p>Dans cet article, nous allons voir comment cr\u00e9er une menu bar utile, performante et bien int\u00e9gr\u00e9e avec SwiftUI, en nous concentrant sur des cas concrets et des bonnes pratiques.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Pourquoi utiliser une menu bar sur macOS ?<\/h2>\n\n\n\n<p>Avant de plonger dans l\u2019impl\u00e9mentation, il est utile de comprendre pourquoi ce type d\u2019interface est particuli\u00e8rement adapt\u00e9 \u00e0 certains outils.<\/p>\n\n\n\n<p>Une application en menu bar r\u00e9pond g\u00e9n\u00e9ralement \u00e0 trois objectifs. D\u2019abord, proposer un acc\u00e8s rapide \u00e0 des fonctionnalit\u00e9s fr\u00e9quentes. C\u2019est typiquement le cas pour un outil de nettoyage de caches, de monitoring ou pour tout utilitaire que l\u2019on veut garder \u00e0 port\u00e9e de clic.<\/p>\n\n\n\n<p>Ensuite, elle \u00e9vite d\u2019encombrer le Dock ou le bureau avec une application compl\u00e8te qui n\u2019a pas besoin d\u2019\u00eatre ouverte en permanence. Enfin, elle offre une exp\u00e9rience fluide et native, parfaitement align\u00e9e avec les usages de macOS.<\/p>\n\n\n\n<p>Dans mon cas, afficher l\u2019espace disque utilis\u00e9 par les caches et proposer un bouton de nettoyage directement depuis la barre de menu \u00e9tait beaucoup plus pertinent qu\u2019une application classique.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Les bases : cr\u00e9er une&nbsp;<code>MenuBarExtra<\/code>&nbsp;avec SwiftUI<\/h2>\n\n\n\n<p>Depuis macOS 13, SwiftUI propose une API d\u00e9di\u00e9e : <code><a href=\"https:\/\/developer.apple.com\/documentation\/SwiftUI\/MenuBarExtra\" data-type=\"link\" data-id=\"https:\/\/developer.apple.com\/documentation\/SwiftUI\/MenuBarExtra\" target=\"_blank\" rel=\"noopener\">MenuBarExtra<\/a><\/code>.<\/p>\n\n\n\n<p>Elle simplifie fortement la cr\u00e9ation d\u2019applications de menu bar, sans devoir s\u2019appuyer directement sur AppKit.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">D\u00e9claration de l\u2019application<\/h3>\n\n\n\n<p>On peut commencer avec une application SwiftUI tr\u00e8s simple, sans fen\u00eatre principale :<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@main\nstruct CacheCleanerApp: App {\n    var body: some Scene {\n        MenuBarExtra(\"Cache Cleaner\", systemImage: \"externaldrive\") {\n            ContentView()\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">@main<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F286C4\">struct<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">CacheCleanerApp<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">App <\/span><span style=\"color: #F6F6F4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> body: <\/span><span style=\"color: #F286C4\">some<\/span><span style=\"color: #F6F6F4\"> Scene {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">MenuBarExtra<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Cache Cleaner<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">systemImage<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">externaldrive<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">ContentView<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Avec cette approche, l\u2019application n\u2019affiche aucune fen\u00eatre principale. Elle vit uniquement dans la menu bar.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-1.png\"><img decoding=\"async\" width=\"217\" height=\"126\" src=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-1.png\" alt=\"menu bar sur macOS\" class=\"wp-image-3198\"\/><\/a><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Construire une interface utile, et pas juste un menu<\/h2>\n\n\n\n<p>Une erreur fr\u00e9quente consiste \u00e0 cr\u00e9er un menu basique avec quelques actions statiques. Cela fonctionne pour des besoins tr\u00e8s simples, mais devient vite limit\u00e9 d\u00e8s que l\u2019on souhaite afficher une interface un peu plus riche.<\/p>\n\n\n\n<p>Mais avec SwiftUI, on peut aller beaucoup plus loin\u2026<\/p>\n\n\n\n<p>Par d\u00e9faut,&nbsp;<code>MenuBarExtra<\/code>&nbsp;se comporte comme un menu classique macOS. Cette structure convient pour une poign\u00e9e d\u2019actions, mais devient contraignante si l\u2019on veut construire quelque chose de plus lisible et plus flexible.<\/p>\n\n\n\n<p>C\u2019est l\u00e0 qu\u2019intervient une option importante :&nbsp;<code>.menuBarExtraStyle(.window)<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">Activer le mode window<\/h3>\n\n\n\n<p>En ajoutant ce modificateur, on transforme le comportement de la menu bar. Au lieu d\u2019un menu classique, on obtient une v\u00e9ritable fen\u00eatre SwiftUI, beaucoup plus souple \u00e0 organiser.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-blur-enabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@main\nstruct CacheCleanerApp: App {\n    var body: some Scene {\n        MenuBarExtra(\"Cache Cleaner\", systemImage: \"externaldrive\") {\n            ContentView()\n        }\n        .menuBarExtraStyle(.window)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F6F6F4\">@<\/span><span style=\"color: #62E884; font-style: italic\">main<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">struct CacheCleanerApp: App {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> body<\/span><span style=\"color: #F286C4\">:<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">some<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">Scene<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #62E884\">MenuBarExtra<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Cache Cleaner<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, systemImage: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">externaldrive<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #62E884\">ContentView<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        }<\/span><\/span>\n<span class=\"line cbp-no-blur\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #62E884\">menuBarExtraStyle<\/span><span style=\"color: #F6F6F4\">(.window)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Avec cette configuration, il devient possible d\u2019utiliser plus librement les composants SwiftUI, comme&nbsp;<code>VStack<\/code>,&nbsp;<code>HStack<\/code>, les s\u00e9parateurs, les \u00e9tats dynamiques ou encore une mise en page plus soign\u00e9e.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">Exemple d\u2019interface<\/h3>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct ContentView: View {\n    var body: some View {\n        VStack(alignment: .leading, spacing: 12) {\n            Text(\"Caches utilis\u00e9s : 12 Go\")\n                .font(.headline)\n            Divider()\n            HStack {\n                Text(\"Android\/Gradle Caches\")\n                Spacer()\n                Button(\"Nettoyer les caches\") {\n                    \/\/ action de nettoyage\n                }\n            }\n            Divider()\n            HStack {\n                Spacer()\n                Menu {\n                    Button(\"\u00c0 propos\") {\n                        \/\/ ouvrir une fen\u00eatre\n                    }\n                } label: {\n                    Image(systemName: \"gearshape\")\n                }\n            }\n        }\n        .padding()\n        .frame(width: 400)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">struct<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">ContentView<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">View <\/span><span style=\"color: #F6F6F4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> body: <\/span><span style=\"color: #F286C4\">some<\/span><span style=\"color: #F6F6F4\"> View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">VStack<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">alignment<\/span><span style=\"color: #F6F6F4\">: .leading, <\/span><span style=\"color: #97E1F1\">spacing<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">12<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">Text<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Caches utilis\u00e9s : 12 Go<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                .<\/span><span style=\"color: #97E1F1\">font<\/span><span style=\"color: #F6F6F4\">(.headline)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">Divider<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">HStack<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Text<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Android\/Gradle Caches<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Spacer<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Button<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Nettoyer les caches<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #7B7F8B\">\/\/ action de nettoyage<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">Divider<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">HStack<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Spacer<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Menu<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #97E1F1\">Button<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">\u00c0 propos<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                        <\/span><span style=\"color: #7B7F8B\">\/\/ ouvrir une fen\u00eatre<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                } <\/span><span style=\"color: #97E1F1\">label<\/span><span style=\"color: #F6F6F4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #97E1F1\">Image<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">systemName<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">gearshape<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">padding<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">frame<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">width<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">400<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Ce type d\u2019interface transforme une simple ic\u00f4ne de menu bar en v\u00e9ritable point d\u2019entr\u00e9e pour l\u2019outil. On n\u2019est plus dans un simple menu technique, mais dans une petite interface claire, rapide et agr\u00e9able \u00e0 utiliser.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-2.png\"><img fetchpriority=\"high\" decoding=\"async\" width=\"428\" height=\"170\" src=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-2.png\" alt=\"menu bar sur macOS\" class=\"wp-image-3201\" srcset=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-2.png 428w, https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-2-420x167.png 420w\" sizes=\"(max-width: 428px) 100vw, 428px\" \/><\/a><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Masquer l\u2019application du Dock et du s\u00e9lecteur d\u2019applications<\/h2>\n\n\n\n<p>Lorsque l\u2019on d\u00e9veloppe une application de menu bar, l\u2019objectif est souvent de la rendre discr\u00e8te et toujours disponible, sans polluer l\u2019interface principale de macOS.<\/p>\n\n\n\n<p>Par d\u00e9faut, m\u00eame avec&nbsp;<code>MenuBarExtra<\/code>, l\u2019application appara\u00eet encore dans le Dock et dans le s\u00e9lecteur d\u2019applications avec&nbsp;<code>Cmd + Tab<\/code>. Pour un utilitaire syst\u00e8me ou un outil de nettoyage de caches, ce comportement n\u2019est pas toujours souhaitable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">Configurer le type d\u2019application<\/h3>\n\n\n\n<p>Pour corriger cela, il faut indiquer \u00e0 macOS que l\u2019application est un agent, autrement dit une application qui fonctionne sans interface principale classique.<\/p>\n\n\n\n<p>Cela se fait dans le fichier&nbsp;<code>Info.plist<\/code>&nbsp;avec la cl\u00e9 suivante :<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&lt;key>LSUIElement&lt;\/key>\n&lt;true\/><\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F6F6F4\">&lt;<\/span><span style=\"color: #F286C4\">key<\/span><span style=\"color: #F6F6F4\">&gt;LSUIElement&lt;\/<\/span><span style=\"color: #F286C4\">key<\/span><span style=\"color: #F6F6F4\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">&lt;<\/span><span style=\"color: #F286C4\">true<\/span><span style=\"color: #F6F6F4\">\/&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Une fois cette option activ\u00e9e, l\u2019application dispara\u00eet du Dock et du s\u00e9lecteur d\u2019applications, tout en restant accessible depuis la menu bar.<\/p>\n\n\n<style>.kb-image3172_0b964b-ba .kb-image-has-overlay:after{opacity:0.3;}.kb-image3172_0b964b-ba img.kb-img, .kb-image3172_0b964b-ba .kb-img img{border-top:1px solid var(--ast-global-color-3);border-right:1px solid var(--ast-global-color-3);border-bottom:1px solid var(--ast-global-color-3);border-left:1px solid var(--ast-global-color-3);}@media all and (max-width: 1024px){.kb-image3172_0b964b-ba img.kb-img, .kb-image3172_0b964b-ba .kb-img img{border-top:1px solid var(--ast-global-color-3);border-right:1px solid var(--ast-global-color-3);border-bottom:1px solid var(--ast-global-color-3);border-left:1px solid var(--ast-global-color-3);}}@media all and (max-width: 767px){.kb-image3172_0b964b-ba img.kb-img, .kb-image3172_0b964b-ba .kb-img img{border-top:1px solid var(--ast-global-color-3);border-right:1px solid var(--ast-global-color-3);border-bottom:1px solid var(--ast-global-color-3);border-left:1px solid var(--ast-global-color-3);}}<\/style>\n<figure class=\"wp-block-kadence-image kb-image3172_0b964b-ba size-full\"><a href=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-3.png\" class=\"kb-advanced-image-link\"><img decoding=\"async\" width=\"600\" height=\"258\" src=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-3.png\" alt=\"MenuBar\" class=\"kb-img wp-image-3205\" srcset=\"https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-3.png 600w, https:\/\/www.kangama.com\/wp-content\/uploads\/2026\/04\/article-menu-bar-3-420x181.png 420w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">Attention aux effets de bord<\/h3>\n\n\n\n<p>Ce mode implique aussi quelques cons\u00e9quences. L\u2019application ne peut plus \u00eatre activ\u00e9e de mani\u00e8re classique, et si vous avez besoin d\u2019ouvrir une fen\u00eatre de pr\u00e9f\u00e9rences, d\u2019aide ou de d\u00e9tails techniques, vous devrez g\u00e9rer explicitement son affichage.<\/p>\n\n\n\n<p>Certaines interactions syst\u00e8me peuvent \u00e9galement demander des ajustements, notamment si votre application repose sur le focus, des raccourcis clavier globaux ou des comportements proches d\u2019une application standard.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Permettre \u00e0 l\u2019utilisateur de quitter l\u2019application proprement<\/h2>\n\n\n\n<p>Une fois l\u2019application masqu\u00e9e du Dock, une question simple devient importante : comment la quitter ?<\/p>\n\n\n\n<p>Dans une application classique, macOS fournit d\u00e9j\u00e0 plusieurs moyens de fermeture. Mais dans une application de menu bar, surtout avec&nbsp;<code>LSUIElement<\/code>, ce point de sortie doit \u00eatre pr\u00e9vu explicitement.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">Ajouter une action Quitter<\/h3>\n\n\n\n<p>La solution la plus simple consiste \u00e0 ajouter un bouton directement dans l\u2019interface :<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>Button(\"Quitter\") {\n    NSApplication.shared.terminate(nil)\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #97E1F1\">Button<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Quitter<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    NSApplication.shared.<\/span><span style=\"color: #97E1F1\">terminate<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #BF9EEE\">nil<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Cette approche est simple, efficace et coh\u00e9rente avec les usages macOS. Elle \u00e9vite \u00e0 l\u2019utilisateur de se retrouver avec une application active sans moyen \u00e9vident de la fermer.<\/p>\n\n\n\n<p>Ce d\u00e9tail peut sembler mineur, mais il joue beaucoup sur la perception de qualit\u00e9. Une application impossible \u00e0 quitter donne tout de suite une impression de manque de finition.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Aller plus loin : ouvrir une fen\u00eatre depuis la menu bar<\/h2>\n\n\n\n<p>M\u00eame si une application de menu bar doit rester l\u00e9g\u00e8re, il peut \u00eatre utile d\u2019ouvrir une fen\u00eatre secondaire pour afficher certaines informations compl\u00e9mentaires. C\u2019est particuli\u00e8rement pertinent pour une vue&nbsp;<em>About<\/em>, une page de pr\u00e9f\u00e9rences, un \u00e9cran d\u2019aide ou des d\u00e9tails techniques.<\/p>\n\n\n\n<p>L\u2019id\u00e9e n\u2019est pas de recr\u00e9er une <strong>application desktop<\/strong> compl\u00e8te, mais d\u2019ajouter quelques fen\u00eatres cibl\u00e9es lorsque cela apporte une vraie valeur.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">D\u00e9clarer une fen\u00eatre d\u00e9di\u00e9e avec SwiftUI<\/h3>\n\n\n\n<p>SwiftUI permet de d\u00e9finir directement une fen\u00eatre nomm\u00e9e dans la structure de l\u2019application. Cela offre une s\u00e9paration claire entre la menu bar et les vues secondaires.<\/p>\n\n\n\n<p>Par exemple, pour afficher une fen\u00eatre&nbsp;<em>About<\/em>, on peut d\u00e9clarer une sc\u00e8ne&nbsp;<code>Window<\/code>&nbsp;d\u00e9di\u00e9e :<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@main\nstruct CacheCleanerApp: App {\n    var body: some Scene {\n        MenuBarExtra(\"Cache Cleaner\", systemImage: \"externaldrive\") {\n            ContentView()\n        }\n        .menuBarExtraStyle(.window)\n\n        Window(\"About DevCacheCleaner\", id: \"about-dev-cache-cleaner\") {\n            AboutView()\n                .windowMinimizeBehavior(.disabled)\n                .containerBackground(.regularMaterial, for: .window)\n        }\n        .windowStyle(.hiddenTitleBar)\n        .windowResizability(.contentSize)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">@main<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F286C4\">struct<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">CacheCleanerApp<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">App <\/span><span style=\"color: #F6F6F4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> body: <\/span><span style=\"color: #F286C4\">some<\/span><span style=\"color: #F6F6F4\"> Scene {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">MenuBarExtra<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Cache Cleaner<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">systemImage<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">externaldrive<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">ContentView<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">menuBarExtraStyle<\/span><span style=\"color: #F6F6F4\">(.window)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">Window<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">About DevCacheCleaner<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">id<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">about-dev-cache-cleaner<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">AboutView<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                .<\/span><span style=\"color: #97E1F1\">windowMinimizeBehavior<\/span><span style=\"color: #F6F6F4\">(.disabled)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                .<\/span><span style=\"color: #97E1F1\">containerBackground<\/span><span style=\"color: #F6F6F4\">(.regularMaterial, <\/span><span style=\"color: #97E1F1\">for<\/span><span style=\"color: #F6F6F4\">: .window)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">windowStyle<\/span><span style=\"color: #F6F6F4\">(.hiddenTitleBar)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">windowResizability<\/span><span style=\"color: #F6F6F4\">(.contentSize)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Cette configuration permet de cr\u00e9er une vraie fen\u00eatre macOS avec une pr\u00e9sentation plus soign\u00e9e et mieux contr\u00f4l\u00e9e qu\u2019une fen\u00eatre standard.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Pourquoi cette configuration est int\u00e9ressante<\/h3>\n\n\n\n<p>Le fait d\u2019utiliser une sc\u00e8ne&nbsp;<code>Window<\/code>&nbsp;avec un identifiant explicite permet d\u2019ouvrir la fen\u00eatre \u00e0 la demande depuis n\u2019importe quelle vue SwiftUI. C\u2019est une solution propre, lisible et bien plus \u00e9l\u00e9gante que de bricoler une ouverture manuelle avec AppKit.<\/p>\n\n\n\n<p>L\u2019utilisation de&nbsp;<code>.windowStyle(.hiddenTitleBar)<\/code>&nbsp;permet d\u2019obtenir une fen\u00eatre plus \u00e9pur\u00e9e, ce qui fonctionne particuli\u00e8rement bien pour une vue&nbsp;<em>About<\/em>&nbsp;ou une petite fen\u00eatre informative.<\/p>\n\n\n\n<p>Avec&nbsp;<code>.windowResizability(.contentSize)<\/code>, la taille s\u2019adapte au contenu, ce qui \u00e9vite les fen\u00eatres surdimensionn\u00e9es. Enfin,&nbsp;<code>.containerBackground(.regularMaterial, for: .window)<\/code>&nbsp;apporte un rendu visuel plus naturel et mieux int\u00e9gr\u00e9 \u00e0 l\u2019esth\u00e9tique r\u00e9cente de macOS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Ouvrir la fen\u00eatre avec&nbsp;<code>openWindow<\/code><\/h3>\n\n\n\n<p>Une fois la fen\u00eatre d\u00e9clar\u00e9e, il suffit d\u2019utiliser&nbsp;<code>openWindow<\/code>&nbsp;pour l\u2019ouvrir depuis la menu bar :<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-blur-enabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct ContentView: View {\n\n    @Environment(\\.openWindow) var openWindow\n    \n    var body: some View {\n        VStack(alignment: .leading, spacing: 12) {\n            Text(\"Caches utilis\u00e9s : 12 Go\")\n                .font(.headline)\n            Divider()\n            HStack {\n                Text(\"Android\/Gradle Caches\")\n                Spacer()\n                Button(\"Nettoyer les caches\") {\n                    \/\/ action de nettoyage\n                }\n            }\n            Divider()\n            HStack {\n                Spacer()\n                Menu {\n                    Button(\"\u00c0 propos\") {\n                        openWindow(id: \"about-dev-cache-cleaner\")\n                    }\n                    Divider()\n                    Button(\"Quit\", systemImage: \"close\") {\n                        NSApp.terminate(nil)\n                    }.keyboardShortcut(\"q\", modifiers: &#91;.control&#93;)\n                } label: {\n                    Image(systemName: \"gearshape\")\n                }\n            }\n        }\n        .padding()\n        .frame(width: 400)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">struct<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">ContentView<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">View <\/span><span style=\"color: #F6F6F4\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-no-blur\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">@Environment<\/span><span style=\"color: #F6F6F4\">(\\.openWindow) <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> openWindow<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> body: <\/span><span style=\"color: #F286C4\">some<\/span><span style=\"color: #F6F6F4\"> View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">VStack<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">alignment<\/span><span style=\"color: #F6F6F4\">: .leading, <\/span><span style=\"color: #97E1F1\">spacing<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">12<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">Text<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Caches utilis\u00e9s : 12 Go<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                .<\/span><span style=\"color: #97E1F1\">font<\/span><span style=\"color: #F6F6F4\">(.headline)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">Divider<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">HStack<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Text<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Android\/Gradle Caches<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Spacer<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Button<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Nettoyer les caches<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #7B7F8B\">\/\/ action de nettoyage<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">Divider<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            <\/span><span style=\"color: #97E1F1\">HStack<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Spacer<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                <\/span><span style=\"color: #97E1F1\">Menu<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line cbp-no-blur\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #97E1F1\">Button<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">\u00c0 propos<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line cbp-no-blur\"><span style=\"color: #F6F6F4\">                        <\/span><span style=\"color: #97E1F1\">openWindow<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">id<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">about-dev-cache-cleaner<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line cbp-no-blur\"><span style=\"color: #F6F6F4\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #97E1F1\">Divider<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #97E1F1\">Button<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Quit<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">systemImage<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">close<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                        NSApp.<\/span><span style=\"color: #97E1F1\">terminate<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #BF9EEE\">nil<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    }.<\/span><span style=\"color: #97E1F1\">keyboardShortcut<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">q<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">modifiers<\/span><span style=\"color: #F6F6F4\">: &#91;.control&#93;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                } <\/span><span style=\"color: #97E1F1\">label<\/span><span style=\"color: #F6F6F4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                    <\/span><span style=\"color: #97E1F1\">Image<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">systemName<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">gearshape<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">padding<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        .<\/span><span style=\"color: #97E1F1\">frame<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">width<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">400<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Cette approche reste totalement dans la logique SwiftUI. On d\u00e9clare une fen\u00eatre avec un identifiant, puis on l\u2019ouvre proprement l\u00e0 o\u00f9 on en a besoin.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\">Garder l\u2019esprit d\u2019une application de menu bar<\/h3>\n\n\n\n<p>Travailler sur une application de menu bar avec SwiftUI montre rapidement que la simplicit\u00e9 apparente cache des choix importants. Passer d\u2019un menu classique \u00e0 une vraie interface avec&nbsp;<code>.menuBarExtraStyle(.window)<\/code>&nbsp;change compl\u00e8tement la mani\u00e8re de concevoir l\u2019outil.<\/p>\n\n\n\n<p>Ce type d\u2019application impose d\u2019aller \u00e0 l\u2019essentiel. L\u2019interface doit \u00eatre rapide, claire et toujours \u00e0 jour, ce qui pousse \u00e0 structurer proprement la gestion de l\u2019\u00e9tat et \u00e0 \u00e9viter toute logique bloquante.<\/p>\n\n\n\n<p>La gestion des fen\u00eatres secondaires avec&nbsp;<code>Window<\/code>&nbsp;et&nbsp;<code>openWindow<\/code>&nbsp;apporte aussi une vraie clart\u00e9 d\u2019architecture, en gardant une s\u00e9paration nette entre les vues principales et les fonctionnalit\u00e9s compl\u00e9mentaires.<\/p>\n\n\n\n<p>Enfin, masquer l\u2019application du Dock transforme la perception du produit. On ne construit plus une application classique, mais un outil discret, pens\u00e9 pour \u00eatre utilis\u00e9 au quotidien sans friction.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Mettre en place une application de menu bar sur macOS avec SwiftUI ne se r\u00e9sume pas \u00e0 afficher quelques actions dans un menu. Avec les bonnes approches, notamment l\u2019utilisation de&nbsp;<code>.menuBarExtraStyle(.window)<\/code>&nbsp;et la gestion de fen\u00eatres secondaires via&nbsp;<code>Window<\/code>, il est possible de construire de v\u00e9ritables outils \u00e0 la fois l\u00e9gers, rapides et agr\u00e9ables \u00e0 utiliser au quotidien.<\/p>\n\n\n\n<p>Ce type d\u2019application est particuli\u00e8rement adapt\u00e9 aux utilitaires d\u00e9veloppeur, comme un outil de nettoyage de caches, o\u00f9 l\u2019acc\u00e8s rapide \u00e0 l\u2019information et aux actions est essentiel. En combinant une interface minimaliste dans la menu bar et des fen\u00eatres d\u00e9di\u00e9es pour les fonctionnalit\u00e9s secondaires, on obtient un bon \u00e9quilibre entre simplicit\u00e9 et puissance.<\/p>\n\n\n\n<p>Mais au-del\u00e0 de la technique, c\u2019est surtout une mani\u00e8re diff\u00e9rente de concevoir un produit. Une <strong>bonne application <\/strong>de <strong>barre de menu<\/strong> ne cherche pas \u00e0 tout faire, mais \u00e0 faire peu de choses, de mani\u00e8re efficace et imm\u00e9diate.<\/p>\n\n\n\n<p>C\u2019est exactement ce type de r\u00e9flexion que j\u2019applique dans <a href=\"https:\/\/www.kangama.com\/creation-applications-ios-android-web\/\" data-type=\"page\" data-id=\"962\"><strong>mes projets<\/strong><\/a> : construire des outils utiles, bien int\u00e9gr\u00e9s, et pens\u00e9s pour \u00eatre r\u00e9ellement utilis\u00e9s.<\/p>\n\n\n\n<p>Si vous travaillez sur un utilitaire macOS ou un outil interne, prendre le temps de concevoir une bonne exp\u00e9rience en menu bar peut faire une vraie diff\u00e9rence sur l\u2019adoption et l\u2019usage au quotidien.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<style>.wp-block-kadence-advancedheading.kt-adv-heading3172_979be6-46, .wp-block-kadence-advancedheading.kt-adv-heading3172_979be6-46[data-kb-block=\"kb-adv-heading3172_979be6-46\"]{font-size:var(--global-kb-font-size-md, 1.25rem);font-style:normal;}.wp-block-kadence-advancedheading.kt-adv-heading3172_979be6-46 mark.kt-highlight, .wp-block-kadence-advancedheading.kt-adv-heading3172_979be6-46[data-kb-block=\"kb-adv-heading3172_979be6-46\"] mark.kt-highlight{font-style:normal;color:#f76a0c;-webkit-box-decoration-break:clone;box-decoration-break:clone;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.wp-block-kadence-advancedheading.kt-adv-heading3172_979be6-46 img.kb-inline-image, .wp-block-kadence-advancedheading.kt-adv-heading3172_979be6-46[data-kb-block=\"kb-adv-heading3172_979be6-46\"] img.kb-inline-image{width:150px;vertical-align:baseline;}<\/style>\n<h4 class=\"kt-adv-heading3172_979be6-46 wp-block-kadence-advancedheading\" data-kb-block=\"kb-adv-heading3172_979be6-46\">Article similaire<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li style=\"margin-top:var(--wp--preset--spacing--20);margin-right:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--20);margin-left:var(--wp--preset--spacing--60)\"><a href=\"https:\/\/www.kangama.com\/outil-macos-nettoyer-cache-developpeur\/\" data-type=\"post\" data-id=\"3105\">Cr\u00e9er un outil macOS pour nettoyer les caches d\u00e9veloppeur : retour d\u2019exp\u00e9rience<\/a><\/li>\n\n\n\n<li style=\"margin-top:var(--wp--preset--spacing--20);margin-right:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--20);margin-left:var(--wp--preset--spacing--60)\"><a href=\"https:\/\/www.kangama.com\/floating-panel-macos-swiftui-nspanel\/\" data-type=\"link\" data-id=\"https:\/\/www.kangama.com\/floating-panel-macos-swiftui-nspanel\/\">Floating Panel sur macOS avec SwiftUI : ouvrir une fen\u00eatre avanc\u00e9e depuis la menu bar<\/a><\/li>\n\n\n\n<li style=\"margin-top:var(--wp--preset--spacing--20);margin-right:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--20);margin-left:var(--wp--preset--spacing--60)\"><a href=\"https:\/\/www.kangama.com\/devcachecleaner-workspace-macos\/\" data-type=\"link\" data-id=\"https:\/\/www.kangama.com\/floating-panel-macos-swiftui-nspanel\/\">DevCacheCleaner 0.2.2-alpha : nettoyer aussi les dossiers g\u00e9n\u00e9r\u00e9s de vos projets<\/a><\/li>\n\n\n\n<li style=\"margin-top:var(--wp--preset--spacing--20);margin-right:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--20);margin-left:var(--wp--preset--spacing--60)\"><a href=\"https:\/\/www.kangama.com\/smappservice-swiftui-app-macos-demarrage\/\" data-type=\"link\" data-id=\"https:\/\/www.kangama.com\/floating-panel-macos-swiftui-nspanel\/\">SMAppService SwiftUI : lancer une application macOS au d\u00e9marrage<\/a><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<style>.kb-row-layout-id3172_c57f9c-35 > .kt-row-column-wrap{align-content:center;}:where(.kb-row-layout-id3172_c57f9c-35 > .kt-row-column-wrap) > .wp-block-kadence-column{justify-content:center;}.kb-row-layout-id3172_c57f9c-35 > .kt-row-column-wrap{column-gap:var(--global-kb-gap-lg, 4rem);row-gap:var(--global-kb-gap-lg, 4rem);max-width:789px;margin-left:auto;margin-right:auto;padding-top:var(--global-kb-spacing-xxl, 5rem);padding-bottom:var(--global-kb-spacing-xxl, 5rem);grid-template-columns:minmax(0, 1fr);}.kb-row-layout-id3172_c57f9c-35{background-color:var(--global-palette8, #F7FAFC);background-image:url('https:\/\/www.kangama.com\/wp-content\/uploads\/2021\/12\/me-contacter-scaled.jpg');background-size:cover;background-position:center center;background-attachment:fixed;background-repeat:no-repeat;}.kb-row-layout-id3172_c57f9c-35 > .kt-row-layout-overlay{opacity:0.50;background-color:var(--ast-global-color-8);}.kb-row-layout-id3172_c57f9c-35 ,.kb-row-layout-id3172_c57f9c-35 h1,.kb-row-layout-id3172_c57f9c-35 h2,.kb-row-layout-id3172_c57f9c-35 h3,.kb-row-layout-id3172_c57f9c-35 h4,.kb-row-layout-id3172_c57f9c-35 h5,.kb-row-layout-id3172_c57f9c-35 h6{color:var(--global-palette3, #1A202C);}.kb-row-layout-id3172_c57f9c-35 a{color:var(--global-palette1, #3182CE);}.kb-row-layout-id3172_c57f9c-35 a:hover{color:var(--global-palette2, #2B6CB0);}@media all and (max-width: 1024px), only screen and (min-device-width: 1024px) and (max-device-width: 1366px) and (-webkit-min-device-pixel-ratio: 2) and (hover: none){.kb-row-layout-id3172_c57f9c-35{background-attachment:scroll;}}@media all and (max-width: 1024px){.kb-row-layout-id3172_c57f9c-35 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}@media all and (max-width: 767px){.kb-row-layout-id3172_c57f9c-35 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}<\/style><div class=\"kb-row-layout-wrap kb-row-layout-id3172_c57f9c-35 alignnone has-theme-palette8-background-color kt-row-has-bg wp-block-kadence-rowlayout\"><div class=\"kt-row-layout-overlay kt-row-overlay-normal\"><\/div><div class=\"kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-middle\">\n<style>.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{display:flex;}.kadence-column3172_a6802f-d9 > .kt-inside-inner-col,.kadence-column3172_a6802f-d9 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}.kadence-column3172_a6802f-d9 > .kt-inside-inner-col > .aligncenter{width:100%;}.kt-row-column-wrap > .kadence-column3172_a6802f-d9{align-self:center;}.kt-inner-column-height-full:not(.kt-has-1-columns) > .wp-block-kadence-column.kadence-column3172_a6802f-d9{align-self:auto;}.kt-inner-column-height-full:not(.kt-has-1-columns) > .wp-block-kadence-column.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}.kadence-column3172_a6802f-d9 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column3172_a6802f-d9{text-align:center;}.kadence-column3172_a6802f-d9{position:relative;}@media all and (max-width: 1024px){.kt-row-column-wrap > .kadence-column3172_a6802f-d9{align-self:center;}}@media all and (max-width: 1024px){.kt-inner-column-height-full:not(.kt-has-1-columns) > .wp-block-kadence-column.kadence-column3172_a6802f-d9{align-self:auto;}}@media all and (max-width: 1024px){.kt-inner-column-height-full:not(.kt-has-1-columns) > .wp-block-kadence-column.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 1024px){.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kt-row-column-wrap > .kadence-column3172_a6802f-d9{align-self:center;}.kt-inner-column-height-full:not(.kt-has-1-columns) > .wp-block-kadence-column.kadence-column3172_a6802f-d9{align-self:auto;}.kt-inner-column-height-full:not(.kt-has-1-columns) > .wp-block-kadence-column.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}.kadence-column3172_a6802f-d9 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column3172_a6802f-d9\"><div class=\"kt-inside-inner-col\"><style>.wp-block-kadence-advancedheading.kt-adv-heading3172_214474-a9, .wp-block-kadence-advancedheading.kt-adv-heading3172_214474-a9[data-kb-block=\"kb-adv-heading3172_214474-a9\"]{margin-top:0px;margin-bottom:var(--global-kb-spacing-lg, 3rem);text-align:center;font-size:var(--global-kb-font-size-lg, 2rem);line-height:1.2em;font-style:normal;}.wp-block-kadence-advancedheading.kt-adv-heading3172_214474-a9 mark.kt-highlight, .wp-block-kadence-advancedheading.kt-adv-heading3172_214474-a9[data-kb-block=\"kb-adv-heading3172_214474-a9\"] mark.kt-highlight{font-style:normal;color:#f76a0c;-webkit-box-decoration-break:clone;box-decoration-break:clone;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.wp-block-kadence-advancedheading.kt-adv-heading3172_214474-a9 img.kb-inline-image, .wp-block-kadence-advancedheading.kt-adv-heading3172_214474-a9[data-kb-block=\"kb-adv-heading3172_214474-a9\"] img.kb-inline-image{width:150px;vertical-align:baseline;}<\/style>\n<h2 class=\"kt-adv-heading3172_214474-a9 wp-block-kadence-advancedheading has-ast-global-color-5-color has-text-color\" data-kb-block=\"kb-adv-heading3172_214474-a9\"><strong><strong>Besoin d\u2019un regard technique sur votre projet ?<\/strong><br>Je peux vous accompagner sur vos d\u00e9veloppements.<\/strong><\/h2>\n\n\n<style>.wp-block-kadence-advancedbtn.kb-btns3172_187e67-59{gap:var(--global-kb-gap-xs, 0.5rem );justify-content:center;align-items:center;}.kt-btns3172_187e67-59 .kt-button{font-weight:normal;font-style:normal;}.kt-btns3172_187e67-59 .kt-btn-wrap-0{margin-right:5px;}.wp-block-kadence-advancedbtn.kt-btns3172_187e67-59 .kt-btn-wrap-0 .kt-button{color:#555555;border-color:#555555;}.wp-block-kadence-advancedbtn.kt-btns3172_187e67-59 .kt-btn-wrap-0 .kt-button:hover, .wp-block-kadence-advancedbtn.kt-btns3172_187e67-59 .kt-btn-wrap-0 .kt-button:focus{color:#ffffff;border-color:#444444;}.wp-block-kadence-advancedbtn.kt-btns3172_187e67-59 .kt-btn-wrap-0 .kt-button::before{display:none;}.wp-block-kadence-advancedbtn.kt-btns3172_187e67-59 .kt-btn-wrap-0 .kt-button:hover, .wp-block-kadence-advancedbtn.kt-btns3172_187e67-59 .kt-btn-wrap-0 .kt-button:focus{background:#444444;}<\/style>\n<div class=\"wp-block-kadence-advancedbtn kb-buttons-wrap kb-btns3172_187e67-59\"><style>ul.menu .wp-block-kadence-advancedbtn .kb-btn3172_6cacac-5e.kb-button{width:initial;}.wp-block-kadence-advancedbtn .kb-btn3172_6cacac-5e.kb-button{color:var(--ast-global-color-7);background:rgba(0,0,0,0);font-weight:bold;text-transform:uppercase;border-top:2px solid var(--ast-global-color-7);border-right:2px solid var(--ast-global-color-7);border-bottom:2px solid var(--ast-global-color-7);border-left:2px solid var(--ast-global-color-7);}.wp-block-kadence-advancedbtn .kb-btn3172_6cacac-5e.kb-button:hover, .wp-block-kadence-advancedbtn .kb-btn3172_6cacac-5e.kb-button:focus{color:var(--ast-global-color-5);background:var(--ast-global-color-7);}@media all and (max-width: 1024px){.wp-block-kadence-advancedbtn .kb-btn3172_6cacac-5e.kb-button{border-top:2px solid var(--ast-global-color-7);border-right:2px solid var(--ast-global-color-7);border-bottom:2px solid var(--ast-global-color-7);border-left:2px solid var(--ast-global-color-7);}}@media all and (max-width: 767px){.wp-block-kadence-advancedbtn .kb-btn3172_6cacac-5e.kb-button{border-top:2px solid var(--ast-global-color-7);border-right:2px solid var(--ast-global-color-7);border-bottom:2px solid var(--ast-global-color-7);border-left:2px solid var(--ast-global-color-7);}}<\/style><a class=\"kb-button kt-button button kb-btn3172_6cacac-5e kt-btn-size-standard kt-btn-width-type-auto kb-btn-global-inherit  kt-btn-has-text-true kt-btn-has-svg-false  wp-block-button__link wp-block-kadence-singlebtn\" href=\"https:\/\/www.kangama.com\/contact\/\"><span class=\"kt-btn-inner-text\">\u00c9changeons sur votre projet<\/span><\/a><\/div>\n<\/div><\/div>\n\n<\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Cr\u00e9er une application de barre de menus(menu bar) macOS avec SwiftUI : guide pratique pour d\u00e9velopper un outil rapide, discret et performant.<\/p>","protected":false},"author":1,"featured_media":3222,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[16],"tags":[],"class_list":["post-3172","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developpement-logiciel-technique"],"_links":{"self":[{"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/posts\/3172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/comments?post=3172"}],"version-history":[{"count":47,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/posts\/3172\/revisions"}],"predecessor-version":[{"id":3547,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/posts\/3172\/revisions\/3547"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/media\/3222"}],"wp:attachment":[{"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/media?parent=3172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/categories?post=3172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kangama.com\/en\/wp-json\/wp\/v2\/tags?post=3172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}