chore: adopted liquid glass 7c72bd4b
Steve · 2025-12-24 16:25 2 file(s) · +76 −61
.claude/settings.local.json (added) +10 −0
1 +
{
2 +
  "permissions": {
3 +
    "allow": [
4 +
      "WebSearch",
5 +
      "WebFetch(domain:www.donnywals.com)",
6 +
      "WebFetch(domain:levelup.gitconnected.com)",
7 +
      "WebFetch(domain:github.com)"
8 +
    ]
9 +
  }
10 +
}
Titan/Views/ContentView.swift +66 −61
53 53
    private let maxRedirects = 5
54 54
55 55
    var body: some View {
56 -
        VStack(spacing: 12) {
57 -
            ScrollViewReader { proxy in
58 -
                ScrollView {
59 -
                    TitanContentView(content: responseText, baseURL: urlText, onLinkTap: { url in
60 -
                        navigateTo(url)
61 -
                    })
62 -
                    .frame(maxWidth: .infinity, alignment: .leading)
63 -
                    .padding(.horizontal, 4)
64 -
                    .id("top")
65 -
                }
66 -
                .onChange(of: responseText) {
67 -
                    withAnimation {
68 -
                        proxy.scrollTo("top", anchor: .top)
69 -
                    }
70 -
                }
71 -
                .ignoresSafeArea(edges: .top)
72 -
                .contentMargins(.top, 60, for: .scrollContent)
56 +
        ScrollViewReader { proxy in
57 +
            ScrollView {
58 +
                TitanContentView(content: responseText, baseURL: urlText, onLinkTap: { url in
59 +
                    navigateTo(url)
60 +
                })
61 +
                .frame(maxWidth: .infinity, alignment: .leading)
62 +
                .padding(.horizontal, 4)
63 +
                .id("top")
73 64
            }
74 -
75 -
            VStack(spacing: 0) {
76 -
                if isLoading {
77 -
                    IndeterminateProgressBar()
78 -
                } else {
79 -
                    Color.clear
80 -
                        .frame(height: 3)
65 +
            .onChange(of: responseText) {
66 +
                withAnimation {
67 +
                    proxy.scrollTo("top", anchor: .top)
81 68
                }
82 -
83 -
                HStack(spacing: 12) {
84 -
                    // Navigation buttons - always visible, grayed out when disabled
85 -
                    Button(action: goBack) {
86 -
                        Image(systemName: "chevron.left")
87 -
                            .font(.title2)
88 -
                            .foregroundColor(canGoBack && !isLoading ? .orange : .gray.opacity(0.4))
69 +
            }
70 +
            .contentMargins(.top, 20, for: .scrollContent)
71 +
            .safeAreaInset(edge: .bottom) {
72 +
                VStack(spacing: 0) {
73 +
                    if isLoading {
74 +
                        IndeterminateProgressBar()
75 +
                    } else {
76 +
                        Color.clear
77 +
                            .frame(height: 3)
89 78
                    }
90 -
                    .disabled(!canGoBack || isLoading)
91 -
                    .padding(.trailing, 8)
92 79
93 -
                    Button(action: goForward) {
94 -
                        Image(systemName: "chevron.right")
95 -
                            .font(.title2)
96 -
                            .foregroundColor(canGoForward && !isLoading ? .orange : .gray.opacity(0.4))
97 -
                    }
98 -
                    .disabled(!canGoForward || isLoading)
80 +
                    GlassEffectContainer {
81 +
                        HStack(spacing: 12) {
82 +
                            // Navigation buttons with glass effect
83 +
                            Button(action: goBack) {
84 +
                                Image(systemName: "chevron.left")
85 +
                                    .font(.title2)
86 +
                                    .foregroundStyle(canGoBack && !isLoading ? .primary : .tertiary)
87 +
                                    .frame(width: 44, height: 44)
88 +
                            }
89 +
                            .disabled(!canGoBack || isLoading)
90 +
                            .glassEffect(.regular.interactive())
99 91
92 +
                            Button(action: goForward) {
93 +
                                Image(systemName: "chevron.right")
94 +
                                    .font(.title2)
95 +
                                    .foregroundStyle(canGoForward && !isLoading ? .primary : .tertiary)
96 +
                                    .frame(width: 44, height: 44)
97 +
                            }
98 +
                            .disabled(!canGoForward || isLoading)
99 +
                            .glassEffect(.regular.interactive())
100 100
101 -
                    TextField("Enter Gemini URL", text: $urlText)
102 -
                        .textFieldStyle(.roundedBorder)
103 -
                        .autocapitalization(.none)
104 -
                        .disableAutocorrection(true)
105 -
                        .keyboardType(.URL)
106 -
                        .submitLabel(.go)
107 -
                        .onSubmit {
108 -
                            navigateTo(urlText)
109 -
                        }
101 +
                            TextField("Enter Gemini URL", text: $urlText)
102 +
                                .autocapitalization(.none)
103 +
                                .disableAutocorrection(true)
104 +
                                .keyboardType(.URL)
105 +
                                .submitLabel(.go)
106 +
                                .onSubmit {
107 +
                                    navigateTo(urlText)
108 +
                                }
109 +
                                .padding(.horizontal, 12)
110 +
                                .padding(.vertical, 10)
111 +
                                .glassEffect(.regular, in: .capsule)
110 112
111 -
                    Menu {
112 -
                        Button {
113 -
                            navigateTo(homeSite)
114 -
                        } label: {
115 -
                            Label("Home", systemImage: "house")
113 +
                            Menu {
114 +
                                Button {
115 +
                                    navigateTo(homeSite)
116 +
                                } label: {
117 +
                                    Label("Home", systemImage: "house")
118 +
                                }
119 +
                            } label: {
120 +
                                Image(systemName: "ellipsis.circle")
121 +
                                    .font(.title2)
122 +
                                    .foregroundStyle(.primary)
123 +
                                    .frame(width: 44, height: 44)
124 +
                            }
125 +
                            .glassEffect(.regular.interactive())
116 126
                        }
117 -
                    } label: {
118 -
                        Image(systemName: "ellipsis.circle")
119 -
                            .font(.title2)
120 -
                            .foregroundColor(.orange)
121 127
                    }
128 +
                    .padding(.top, 8)
122 129
                }
123 -
                .padding(.top, 8)
130 +
                .padding(.horizontal, 20)
131 +
                .padding(.bottom, 8)
124 132
            }
125 -
            .padding(.horizontal, 30)
126 -
            .padding(.bottom, 8)
127 133
        }
128 134
        .onAppear {
129 135
            navigateTo(homeSite)
130 136
        }
131 -
        .ignoresSafeArea(edges: .top)
132 137
        .alert("Input Required", isPresented: $showInputPrompt) {
133 138
            if inputIsSensitive {
134 139
                SecureField("Enter input", text: $inputValue)