Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ora/Models/Folder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ class Folder: ObservableObject, Identifiable {
var id: UUID
var name: String
var isOpened: Bool
var order: Int

@Relationship(deleteRule: .nullify) var tabs: [Tab] = []
@Relationship(inverse: \TabContainer.folders) var container: TabContainer
init(
id: UUID = UUID(),
name: String,
isOpened: Bool = false,
order: Int = 0,
container: TabContainer
) {
self.id = UUID()
self.id = id
self.name = name
self.isOpened = isOpened
self.order = order
self.container = container
}
}
9 changes: 9 additions & 0 deletions ora/Models/Tab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Tab: ObservableObject, Identifiable {
var urlString: String
var savedURL: URL?
var title: String
var customTitle: String? // User-defined custom title
var favicon: URL? // Add favicon property
var createdAt: Date
var lastAccessedAt: Date?
Expand Down Expand Up @@ -52,11 +53,13 @@ class Tab: ObservableObject, Identifiable {
@Transient @Published var hoveredLinkURL: String?

@Relationship(inverse: \TabContainer.tabs) var container: TabContainer
@Relationship(inverse: \Folder.tabs) var folder: Folder?

init(
id: UUID = UUID(),
url: URL,
title: String,
customTitle: String? = nil,
favicon: URL? = nil,
container: TabContainer,
type: TabType = .normal,
Expand All @@ -72,6 +75,7 @@ class Tab: ObservableObject, Identifiable {
self.urlString = url.absoluteString

self.title = title
self.customTitle = customTitle
self.favicon = favicon
self.createdAt = nowDate
self.lastAccessedAt = nowDate
Expand Down Expand Up @@ -117,6 +121,11 @@ class Tab: ObservableObject, Identifiable {
}
}

// Computed property to get the title to display (custom title takes precedence)
var displayTitle: String {
return customTitle ?? title
}

func syncBackgroundColorFromHex() {
backgroundColor = Color(hex: backgroundColorHex)
}
Expand Down
2 changes: 1 addition & 1 deletion ora/Modules/Launcher/Main/LauncherMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ struct LauncherMain: View {
suggestions.append(
LauncherSuggestion(
type: .openedTab,
title: tab.title,
title: tab.displayTitle,
url: tab.url,
faviconURL: tab.favicon,
faviconLocalFile: tab.faviconLocalFile,
Expand Down
48 changes: 47 additions & 1 deletion ora/Modules/Sidebar/ContainerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ struct ContainerView: View {
@EnvironmentObject var appState: AppState
@EnvironmentObject var tabManager: TabManager
@State private var draggedItem: UUID?
@State private var showCreateFolderDialog = false
@State private var newFolderName = ""

var body: some View {
VStack(alignment: .leading, spacing: 16) {
Expand Down Expand Up @@ -36,8 +38,24 @@ struct ContainerView: View {
containers: containers
)
Divider()

// Display folders
ForEach(folders) { folder in
FolderView(
folder: folder,
draggedItem: $draggedItem,
onDrag: dragTab,
onSelect: selectTab,
onPinToggle: togglePin,
onFavoriteToggle: toggleFavorite,
onClose: removeTab,
onMoveToContainer: moveTab,
availableContainers: containers
)
}

NormalTabsList(
tabs: normalTabs,
tabs: normalTabsNotInFolders,
draggedItem: $draggedItem,
onDrag: dragTab,
onSelect: selectTab,
Expand All @@ -51,6 +69,23 @@ struct ContainerView: View {
}
}
.modifier(WindowDragIfAvailable())
.contextMenu {
Button("Create New Folder") {
showCreateFolderDialog = true
}
}
.sheet(isPresented: $showCreateFolderDialog) {
CreateFolderSheet(
isPresented: $showCreateFolderDialog,
folderName: $newFolderName,
onCreate: {
if !newFolderName.isEmpty {
_ = tabManager.createFolder(name: newFolderName, in: container)
newFolderName = ""
}
}
)
}
}

private var favoriteTabs: [Tab] {
Expand All @@ -70,6 +105,17 @@ struct ContainerView: View {
.sorted(by: { $0.order > $1.order })
.filter { $0.type == .normal }
}

private var normalTabsNotInFolders: [Tab] {
return container.tabs
.sorted(by: { $0.order > $1.order })
.filter { $0.type == .normal && $0.folder == nil }
}

private var folders: [Folder] {
return container.folders
.sorted(by: { $0.order < $1.order })
}

private func addNewTab() {
appState.showLauncher = true
Expand Down
52 changes: 52 additions & 0 deletions ora/Modules/Sidebar/CreateFolderSheet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import SwiftUI

struct CreateFolderSheet: View {
@Binding var isPresented: Bool
@Binding var folderName: String
let onCreate: () -> Void

@Environment(\.theme) private var theme
@FocusState private var isFocused: Bool

var body: some View {
VStack(spacing: 20) {
Text("Create New Folder")
.font(.headline)
.foregroundColor(theme.foreground)

TextField("Folder name", text: $folderName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.focused($isFocused)
.onSubmit {
if !folderName.isEmpty {
onCreate()
isPresented = false
}
}

HStack(spacing: 12) {
Button("Cancel") {
folderName = ""
isPresented = false
}
.keyboardShortcut(.escape)

Button("Create") {
if !folderName.isEmpty {
onCreate()
isPresented = false
}
}
.keyboardShortcut(.return)
.disabled(folderName.isEmpty)
}
}
.padding()
.frame(width: 300)
.background(theme.solidWindowBackgroundColor)
.onAppear {
folderName = "New Folder"
isFocused = true
}
}
}
Loading