| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- import AppKit
- import SwiftUI
- private let sheetsAccent = Color(red: 0.13, green: 0.59, blue: 0.38)
- private let sheetsPanelBg = Color(red: 0.06, green: 0.12, blue: 0.09)
- private enum SheetsCreateURL {
- static let newSheet = "https://sheets.new"
- static let templates = "https://docs.google.com/templates?type=spreadsheets"
- static let homeList = "https://docs.google.com/spreadsheets/u/0/"
- }
- /// Large Google Sheets dashboard: find + create (same pattern as Forms).
- struct SheetsDesktopWidgetView: View {
- let app: LauncherApp
- let mode: SheetsWidgetMode
- var isPreview: Bool = false
- @State private var findText: String = ""
- var body: some View {
- Group {
- switch mode {
- case .dashboard:
- dashboardBody
- }
- }
- .clipShape(RoundedRectangle(cornerRadius: 22, style: .continuous))
- }
- private var dashboardBody: some View {
- ZStack(alignment: .topLeading) {
- LinearGradient(
- colors: [
- Color(red: 0.08, green: 0.32, blue: 0.22),
- sheetsPanelBg,
- ],
- startPoint: .topLeading,
- endPoint: .bottomTrailing
- )
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- VStack(alignment: .leading, spacing: 12) {
- headerRow
- findFieldRow
- createRow
- Spacer(minLength: 0)
- }
- .padding(14)
- .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
- .disabled(isPreview)
- .opacity(isPreview ? 0.88 : 1)
- }
- private var headerRow: some View {
- HStack(spacing: 8) {
- AppIconView(app: app, size: 30, showAppBackground: false, iconPaddingFactor: 0.08)
- VStack(alignment: .leading, spacing: 2) {
- Text("Google Sheets")
- .font(.system(size: 14, weight: .bold))
- .foregroundStyle(.white.opacity(0.95))
- Text("Dashboard")
- .font(.system(size: 10, weight: .semibold))
- .foregroundStyle(.white.opacity(0.55))
- }
- Spacer(minLength: 0)
- Button(action: { openAbsolute(SheetsCreateURL.homeList) }) {
- Image(systemName: "arrow.up.right.square")
- .font(.system(size: 14, weight: .semibold))
- .foregroundStyle(.white.opacity(0.9))
- .padding(8)
- .background(Circle().fill(Color.white.opacity(0.12)))
- }
- .buttonStyle(.plain)
- .help("Open Google Sheets")
- }
- }
- private var findFieldRow: some View {
- HStack(spacing: 8) {
- Image(systemName: "magnifyingglass")
- .font(.system(size: 13, weight: .semibold))
- .foregroundStyle(.white.opacity(0.5))
- TextField("Find spreadsheets", text: $findText)
- .textFieldStyle(.plain)
- .font(.system(size: 13, weight: .medium))
- .foregroundStyle(.white.opacity(0.95))
- .onSubmit { submitFind() }
- Button("Go", action: submitFind)
- .font(.system(size: 11, weight: .bold))
- .buttonStyle(.borderedProminent)
- .tint(sheetsAccent)
- .controlSize(.small)
- }
- .padding(.horizontal, 10)
- .padding(.vertical, 8)
- .background(RoundedRectangle(cornerRadius: 12, style: .continuous).fill(Color.white.opacity(0.1)))
- }
- private var createRow: some View {
- VStack(alignment: .leading, spacing: 6) {
- sectionLabel("Create")
- HStack(spacing: 6) {
- createPill(title: "Sheet", systemImage: "tablecells", urlString: SheetsCreateURL.newSheet, help: "New spreadsheet (sheets.new)")
- createPill(title: "Templates", systemImage: "square.grid.2x2", urlString: SheetsCreateURL.templates, help: "Spreadsheet templates")
- createPill(title: "Browse", systemImage: "folder", urlString: SheetsCreateURL.homeList, help: "All spreadsheets")
- }
- }
- }
- private func createPill(title: String, systemImage: String, urlString: String, help: String) -> some View {
- Button {
- openAbsolute(urlString)
- } label: {
- VStack(spacing: 4) {
- Image(systemName: systemImage)
- .font(.system(size: 16, weight: .semibold))
- Text(title)
- .font(.system(size: 10, weight: .bold))
- }
- .foregroundStyle(.white.opacity(0.92))
- .frame(maxWidth: .infinity)
- .padding(.vertical, 10)
- .background(RoundedRectangle(cornerRadius: 12, style: .continuous).fill(Color.white.opacity(0.1)))
- .overlay(
- RoundedRectangle(cornerRadius: 12, style: .continuous)
- .strokeBorder(Color.white.opacity(0.08), lineWidth: 1)
- )
- }
- .buttonStyle(.plain)
- .help(help)
- }
- private func sectionLabel(_ text: String) -> some View {
- Text(text)
- .font(.system(size: 10, weight: .bold))
- .foregroundStyle(.white.opacity(0.45))
- .textCase(.uppercase)
- }
- private func submitFind() {
- NSApp.activate(ignoringOtherApps: true)
- let q = findText.trimmingCharacters(in: .whitespacesAndNewlines)
- var c = URLComponents(string: SheetsCreateURL.homeList)!
- if !q.isEmpty {
- c.queryItems = [URLQueryItem(name: "q", value: q)]
- }
- guard let url = c.url else { return }
- openInApp(url)
- }
- private func openAbsolute(_ urlString: String) {
- guard let url = URL(string: urlString) else { return }
- NSApp.activate(ignoringOtherApps: true)
- openInApp(url)
- }
- private func openInApp(_ url: URL) {
- InAppBrowserWindowManager.shared.open(url: url, title: app.name)
- }
- }
|