chore: adopted liquid glass
7c72bd4b
2 file(s) · +76 −61
| 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 | + | } |
| 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) |