Comece pelo modelo de cenas do Mac
Use este fluxo para transformar sua ideia na estrutura de um aplicativo para Mac, com uma interface pensada para o desktop desde o início. Assim, você evita ter que adaptar uma pilha de navegação projetada para telas sensíveis ao toque. Peça ao Codex que escolha primeiro o modelo de cenas e depois projete a janela principal com uma barra lateral que mantenha o item selecionado, um painel de detalhes e um inspetor para controles secundários ou metadados.

Use o plugin Build macOS Apps quando quiser que o Codex aplique essa estrutura de desktop e use o shell como principal meio de compilar e executar o aplicativo. A habilidade do plugin que reúne padrões de SwiftUI para macOS ajuda a projetar cenas, barras laterais, inspetores, comandos e ajustes. Ela também ajuda a criar pequenas integrações com o AppKit quando falta ao SwiftUI algum comportamento específico do Mac.
Crie uma barra lateral, um painel de detalhes e um inspetor
Prefira NavigationSplitView quando for vantajoso manter a navegação sempre disponível e preservar a seleção do item. Use linhas nativas e simples na barra lateral, mantenha os fundos fornecidos pelo sistema e reserve os cartões personalizados ou conjuntos extensos de metadados para o painel de detalhes ou o inspetor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62import SwiftUI
struct Item: Identifiable, Hashable {
let id: String
let title: String
let systemImage: String
}
let items = [Item(id: "notes", title: "Notes", systemImage: "note.text"), Item(id: "photos", title: "Photos", systemImage: "photo")]
struct ItemDetailView: View {
let selection: String?
var body: some View { Text(selection ?? "Select an item").frame(maxWidth: .infinity, maxHeight: .infinity) }
}
struct ItemInspectorView: View {
let selection: String?
var body: some View { Text("Metadata: \(selection ?? "No selection")").padding().frame(minWidth: 220) }
}
@MainActor final class LibraryStore: ObservableObject {
@Published var entries = items
@Published var selection: String?
@Published var showInspector = true
func addItem() {
let item = Item(id: UUID().uuidString, title: "New Item", systemImage: "doc")
entries.append(item)
selection = item.id
}
}
struct LibraryRootView: View {
@StateObject private var store = LibraryStore()
@SceneStorage("LibraryRootView.selection") private var savedSelection: Item.ID?
@SceneStorage("LibraryRootView.showInspector") private var savedShowInspector = true
var body: some View {
NavigationSplitView {
List(selection: $store.selection) {
ForEach(store.entries) { item in
Label(item.title, systemImage: item.systemImage)
.tag(item.id)
}
}
.listStyle(.sidebar)
.navigationTitle("Library")
} detail: {
ItemDetailView(selection: store.selection)
.inspector(isPresented: $store.showInspector) {
ItemInspectorView(selection: store.selection)
}
}
.focusedSceneObject(store)
.onAppear {
store.selection = savedSelection
store.showInspector = savedShowInspector
}
.onChange(of: store.selection) { _, selection in
savedSelection = selection
}
.onChange(of: store.showInspector) { _, showInspector in
savedShowInspector = showInspector
}
}
}
Se o aplicativo exigir dimensões fora do padrão para os painéis, coordenação de janelas em baixo nível ou um comportamento personalizado na cadeia de resposta a eventos, peça ao Codex que preserve a estrutura em SwiftUI e integre o AppKit apenas na medida necessária para atender a esse requisito.
Integre comandos, barras de ferramentas e atalhos à interface de desktop
Quem usa o Mac deve conseguir encontrar as ações importantes na barra de menus e na barra de ferramentas, além de descobrir os atalhos de teclado correspondentes. Peça ao Codex que associe commands no nível da cena, itens de menu que variam conforme o contexto e botões da barra de ferramentas às mesmas ações do aplicativo. Assim, quem usa o desktop não precisa procurar controles acessíveis apenas por gestos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28@main
struct LibraryApp: App {
@FocusedObject private var store: LibraryStore?
var body: some Scene {
WindowGroup {
LibraryRootView()
}
.commands {
CommandMenu("Library") {
Button("New Item") {
store?.addItem()
}
.keyboardShortcut("n")
.disabled(store == nil)
Button("Toggle Inspector") {
store?.showInspector.toggle()
}
.keyboardShortcut("i", modifiers: [.command, .option])
.disabled(store == nil)
}
}
Settings {
LibrarySettingsView()
}
}
}
Use FocusedValue, o estado da cena ou um estado de seleção explícito quando o comando precisar atuar sobre o item exibido no painel de detalhes. Se um atalho for registrado em mais de um lugar, peça ao Codex que centralize o registro para que o aplicativo encaminhe o comando por um único caminho bem definido.
Mantenha as preferências em Settings
Para as preferências do aplicativo, use uma cena dedicada do tipo Settings e salve com @AppStorage as escolhas do usuário que devem persistir entre sessões. No Mac, essa abordagem costuma ser mais adequada do que adicionar uma tela de ajustes à pilha de navegação da janela principal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14struct LibrarySettingsView: View {
@AppStorage("showItemMetadata") private var showItemMetadata = true
var body: some View {
TabView {
Form {
Toggle("Show Item Metadata", isOn: $showItemMetadata)
}
.tabItem { Label("General", systemImage: "gearshape") }
}
.frame(width: 460, height: 260)
.scenePadding()
}
}
Descreva a ideia do aplicativo no prompt e valide a estrutura
Para aproveitar melhor este fluxo, descreva no prompt a ideia do aplicativo, os principais objetos de conteúdo e as ações mais importantes. Em seguida, peça ao Codex que comece criando a estrutura de desktop para esse fluxo de trabalho. Peça ao agente que faça uma verificação rápida compilando e executando o aplicativo. Depois, peça que resuma como as cenas estão organizadas, como os comandos se conectam às ações, quais componentes gerenciam o estado e em que pontos foi preciso integrar o AppKit.
Dicas práticas
Mantenha a barra lateral nativa
Em cada linha da barra lateral, use um ícone, um título de uma linha e, no máximo, uma linha curta de texto secundário. Coloque cartões mais detalhados, contadores e metadados no painel de detalhes ou no inspetor para que seja fácil identificar os itens na barra lateral.
Evite esconder os ajustes na pilha de navegação principal
Se uma preferência do usuário afetar todo o aplicativo, peça ao Codex que coloque o controle correspondente em Settings, use @AppStorage para salvar a preferência e ofereça acesso aos ajustes pelo menu do aplicativo. Isso evita acrescentar outra tela de ajustes à pilha de navegação.
Reserve o AppKit para necessidades específicas do desktop
Se o recurso exigir painéis para abrir ou salvar arquivos, controle sobre qual componente recebe os eventos primeiro ou uma NSView personalizada, limite o uso do AppKit a essa integração. Mantenha o modelo de estado sob o controle do SwiftUI, sem reescrever a janela inteira em AppKit.