Commit 5b4208dbee
Verified · cmc
Layout: unified · split
App/Sources/LaunchesScreen.swift +18 −18
| @@ -18,11 +18,11 @@ struct LaunchesScreen: View { | |||
| 18 | var body: some View { | 18 | var body: some View { |
| 19 | ScrollView { | 19 | ScrollView { |
| 20 | VStack(alignment: .leading, spacing: 0) { | 20 | VStack(alignment: .leading, spacing: 0) { |
| 21 | Text("Launches").font(.system(size: 28, weight: .medium)) | 21 | Text("Launches").font(.title.weight(.medium)) |
| 22 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 8).padding(.bottom, 8) | 22 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 8).padding(.bottom, 8) |
| 23 | 23 | ||
| 24 | if let error { | 24 | if let error { |
| 25 | Text(error).font(.system(size: 13)).foregroundStyle(accent).padding(.vertical, 12) | 25 | Text(error).font(.footnote).foregroundStyle(accent).padding(.vertical, 12) |
| 26 | } | 26 | } |
| 27 | if let list { | 27 | if let list { |
| 28 | ForEach(Array(list.launches.enumerated()), id: \.element.id) { i, launch in | 28 | ForEach(Array(list.launches.enumerated()), id: \.element.id) { i, launch in |
| @@ -30,7 +30,7 @@ struct LaunchesScreen: View { | |||
| 30 | .buttonStyle(.plain) | 30 | .buttonStyle(.plain) |
| 31 | } | 31 | } |
| 32 | Text("Launch data: The Space Devs, Launch Library 2.") | 32 | Text("Launch data: The Space Devs, Launch Library 2.") |
| 33 | .font(.system(size: 10)).opacity(0.5).padding(.vertical, 16) | 33 | .font(.caption2).opacity(0.5).padding(.vertical, 16) |
| 34 | } else if error == nil { | 34 | } else if error == nil { |
| 35 | ProgressView().tint(ink).padding(.top, 40).frame(maxWidth: .infinity) | 35 | ProgressView().tint(ink).padding(.top, 40).frame(maxWidth: .infinity) |
| 36 | } | 36 | } |
| @@ -57,18 +57,18 @@ struct LaunchesScreen: View { | |||
| 57 | private func row(_ l: Launch, index: Int) -> some View { | 57 | private func row(_ l: Launch, index: Int) -> some View { |
| 58 | VStack(alignment: .leading, spacing: 6) { | 58 | VStack(alignment: .leading, spacing: 6) { |
| 59 | HStack(alignment: .firstTextBaseline) { | 59 | HStack(alignment: .firstTextBaseline) { |
| 60 | Text(String(format: "%02d", index)).font(.system(size: 10).monospacedDigit()).opacity(0.5) | 60 | Text(String(format: "%02d", index)).font(.caption2.monospacedDigit()).opacity(0.5) |
| 61 | Text(l.net.formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated).hour().minute())) | 61 | Text(l.net.formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated).hour().minute())) |
| 62 | .font(.system(size: 11)).opacity(0.7) | 62 | .font(.caption2).opacity(0.7) |
| 63 | Spacer() | 63 | Spacer() |
| 64 | StatusTag(status: l.status, ink: ink, accent: accent) | 64 | StatusTag(status: l.status, ink: ink, accent: accent) |
| 65 | } | 65 | } |
| 66 | Text(l.rocket).font(.system(size: 22, weight: .medium)) | 66 | Text(l.rocket).font(.title2.weight(.medium)) |
| 67 | if let m = l.mission { Text(m).font(.system(size: 14)).lineLimit(1) } | 67 | if let m = l.mission { Text(m).font(.subheadline).lineLimit(1) } |
| 68 | HStack { | 68 | HStack { |
| 69 | Text("\(l.provider) · \(l.location)").font(.system(size: 11)).opacity(0.6).lineLimit(1) | 69 | Text("\(l.provider) · \(l.location)").font(.caption2).opacity(0.6).lineLimit(1) |
| 70 | Spacer() | 70 | Spacer() |
| 71 | Countdown(to: l.net).font(.system(size: 13, weight: .medium).monospacedDigit()) | 71 | Countdown(to: l.net).font(.footnote.weight(.medium).monospacedDigit()) |
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | .padding(.vertical, 14) | 74 | .padding(.vertical, 14) |
| @@ -84,7 +84,7 @@ struct StatusTag: View { | |||
| 84 | 84 | ||
| 85 | var body: some View { | 85 | var body: some View { |
| 86 | Text(status.uppercased()) | 86 | Text(status.uppercased()) |
| 87 | .font(.system(size: 10, weight: .medium)) | 87 | .font(.caption2.weight(.medium)) |
| 88 | .tracking(0.6) | 88 | .tracking(0.6) |
| 89 | .padding(.horizontal, 6).padding(.vertical, 2) | 89 | .padding(.horizontal, 6).padding(.vertical, 2) |
| 90 | .foregroundStyle(status == "Go" ? Color.black : ink) | 90 | .foregroundStyle(status == "Go" ? Color.black : ink) |
| @@ -121,11 +121,11 @@ struct LaunchDetail: View { | |||
| 121 | VStack(alignment: .leading, spacing: 10) { | 121 | VStack(alignment: .leading, spacing: 10) { |
| 122 | HStack { | 122 | HStack { |
| 123 | StatusTag(status: launch.status, ink: ink, accent: accent) | 123 | StatusTag(status: launch.status, ink: ink, accent: accent) |
| 124 | Text(launch.statusName).font(.system(size: 12)).opacity(0.7) | 124 | Text(launch.statusName).font(.caption).opacity(0.7) |
| 125 | } | 125 | } |
| 126 | Text(launch.rocket).font(.system(size: 28, weight: .medium)) | 126 | Text(launch.rocket).font(.title.weight(.medium)) |
| 127 | if let m = launch.mission { Text(m).font(.system(size: 17)) } | 127 | if let m = launch.mission { Text(m).font(.body) } |
| 128 | Countdown(to: launch.net).font(.system(size: 34, weight: .medium).monospacedDigit()).padding(.vertical, 6) | 128 | Countdown(to: launch.net).font(.largeTitle.weight(.medium).monospacedDigit()).padding(.vertical, 6) |
| 129 | Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 6) { | 129 | Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 6) { |
| 130 | fact("Provider", launch.provider) | 130 | fact("Provider", launch.provider) |
| 131 | fact("Launch time", launch.net.formatted(date: .abbreviated, time: .shortened)) | 131 | fact("Launch time", launch.net.formatted(date: .abbreviated, time: .shortened)) |
| @@ -137,11 +137,11 @@ struct LaunchDetail: View { | |||
| 137 | fact("Pad", launch.pad) | 137 | fact("Pad", launch.pad) |
| 138 | fact("Location", launch.location) | 138 | fact("Location", launch.location) |
| 139 | } | 139 | } |
| 140 | .font(.system(size: 14)) | 140 | .font(.subheadline) |
| 141 | followButton.padding(.top, 8) | 141 | followButton.padding(.top, 8) |
| 142 | if let message { Text(message).font(.system(size: 12)).opacity(0.7) } | 142 | if let message { Text(message).font(.caption).opacity(0.7) } |
| 143 | if let d = launch.missionDescription { | 143 | if let d = launch.missionDescription { |
| 144 | Text(d).font(.system(size: 14)).opacity(0.85).padding(.top, 8) | 144 | Text(d).font(.subheadline).opacity(0.85).padding(.top, 8) |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | .padding(20) | 147 | .padding(20) |
| @@ -160,7 +160,7 @@ struct LaunchDetail: View { | |||
| 160 | following ? unfollow() : follow() | 160 | following ? unfollow() : follow() |
| 161 | } label: { | 161 | } label: { |
| 162 | Label(following ? "Stop following" : "Follow on Lock Screen", systemImage: following ? "bell.slash" : "bell") | 162 | Label(following ? "Stop following" : "Follow on Lock Screen", systemImage: following ? "bell.slash" : "bell") |
| 163 | .font(.system(size: 15, weight: .medium)) | 163 | .font(.subheadline.weight(.medium)) |
| 164 | .frame(maxWidth: .infinity) | 164 | .frame(maxWidth: .infinity) |
| 165 | .padding(.vertical, 10) | 165 | .padding(.vertical, 10) |
| 166 | .overlay(RoundedRectangle(cornerRadius: 6).stroke(ink.opacity(0.5), lineWidth: 0.5)) | 166 | .overlay(RoundedRectangle(cornerRadius: 6).stroke(ink.opacity(0.5), lineWidth: 0.5)) |
App/Sources/LibraryScreen.swift +8 −8
| @@ -17,9 +17,9 @@ struct LibraryScreen: View { | |||
| 17 | if !pages.isEmpty { | 17 | if !pages.isEmpty { |
| 18 | NavigationLink(value: section) { | 18 | NavigationLink(value: section) { |
| 19 | HStack { | 19 | HStack { |
| 20 | Text(section.title).font(.system(size: 17)) | 20 | Text(section.title).font(.body) |
| 21 | Spacer() | 21 | Spacer() |
| 22 | Text("\(pages.count)").font(.system(size: 13).monospacedDigit()).opacity(0.5) | 22 | Text("\(pages.count)").font(.footnote.monospacedDigit()).opacity(0.5) |
| 23 | } | 23 | } |
| 24 | } | 24 | } |
| 25 | .listRowBackground(pageBackground) | 25 | .listRowBackground(pageBackground) |
| @@ -66,7 +66,7 @@ struct PageRow: View { | |||
| 66 | var body: some View { | 66 | var body: some View { |
| 67 | VStack(alignment: .leading, spacing: 2) { | 67 | VStack(alignment: .leading, spacing: 2) { |
| 68 | Text(page.title).font(.body) | 68 | Text(page.title).font(.body) |
| 69 | Text(page.subtitle).font(.system(size: 12)).opacity(0.6).lineLimit(1) | 69 | Text(page.subtitle).font(.caption).opacity(0.6).lineLimit(1) |
| 70 | } | 70 | } |
| 71 | .padding(.vertical, 2) | 71 | .padding(.vertical, 2) |
| 72 | } | 72 | } |
| @@ -78,7 +78,7 @@ struct LibraryPageView: View { | |||
| 78 | var body: some View { | 78 | var body: some View { |
| 79 | ScrollView { | 79 | ScrollView { |
| 80 | VStack(alignment: .leading, spacing: 0) { | 80 | VStack(alignment: .leading, spacing: 0) { |
| 81 | Text(page.section.title).font(.system(size: 11, weight: .medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) | 81 | Text(page.section.title).font(.caption2.weight(.medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) |
| 82 | Text(page.title).font(.largeTitle.weight(.medium)).padding(.top, 4) | 82 | Text(page.title).font(.largeTitle.weight(.medium)).padding(.top, 4) |
| 83 | Text(page.subtitle).font(.subheadline).opacity(0.75).padding(.top, 2) | 83 | Text(page.subtitle).font(.subheadline).opacity(0.75).padding(.top, 2) |
| 84 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 10).padding(.bottom, 16) | 84 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 10).padding(.bottom, 16) |
| @@ -121,23 +121,23 @@ struct LibraryPageView: View { | |||
| 121 | AsyncImage(url: image.url) { phase in | 121 | AsyncImage(url: image.url) { phase in |
| 122 | switch phase { | 122 | switch phase { |
| 123 | case .success(let img): img.resizable().scaledToFit() | 123 | case .success(let img): img.resizable().scaledToFit() |
| 124 | case .failure: Color.black.frame(height: 120).overlay(Text("Image unavailable").font(.system(size: 12)).opacity(0.6)) | 124 | case .failure: Color.black.frame(height: 120).overlay(Text("Image unavailable").font(.caption).opacity(0.6)) |
| 125 | default: Color.black.frame(height: 200).overlay(ProgressView().tint(ink)) | 125 | default: Color.black.frame(height: 200).overlay(ProgressView().tint(ink)) |
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | Text(image.caption).font(.footnote).opacity(0.75) | 128 | Text(image.caption).font(.footnote).opacity(0.75) |
| 129 | Link(destination: image.page) { | 129 | Link(destination: image.page) { |
| 130 | Text("\(image.credit) · \(image.licence)").font(.system(size: 10)).opacity(0.55) | 130 | Text("\(image.credit) · \(image.licence)").font(.caption2).opacity(0.55) |
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | private var sources: some View { | 135 | private var sources: some View { |
| 136 | VStack(alignment: .leading, spacing: 6) { | 136 | VStack(alignment: .leading, spacing: 6) { |
| 137 | Text("Sources").font(.system(size: 11, weight: .medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) | 137 | Text("Sources").font(.caption2.weight(.medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) |
| 138 | ForEach(Array(page.sources.enumerated()), id: \.offset) { i, s in | 138 | ForEach(Array(page.sources.enumerated()), id: \.offset) { i, s in |
| 139 | Link(destination: s.url) { | 139 | Link(destination: s.url) { |
| 140 | Text("\(i + 1). \(s.title)").font(.system(size: 12)).underline().opacity(0.8) | 140 | Text("\(i + 1). \(s.title)").font(.caption).underline().opacity(0.8) |
| 141 | } | 141 | } |
| 142 | } | 142 | } |
| 143 | } | 143 | } |
App/Sources/SkyScreen.swift +12 −10
| @@ -123,13 +123,15 @@ struct SkyScreen: View { | |||
| 123 | HStack(alignment: .top) { | 123 | HStack(alignment: .top) { |
| 124 | VStack(alignment: .leading, spacing: 4) { | 124 | VStack(alignment: .leading, spacing: 4) { |
| 125 | Text(model.offsetHours == 0 ? "Tonight" : "Sky at \(model.displayedDate.formatted(date: .omitted, time: .shortened))") | 125 | Text(model.offsetHours == 0 ? "Tonight" : "Sky at \(model.displayedDate.formatted(date: .omitted, time: .shortened))") |
| 126 | .font(.system(size: 22, weight: .medium)) | 126 | .font(.title2.weight(.medium)) |
| 127 | Text(model.placeName) | 127 | Text(model.placeName) |
| 128 | .font(.system(size: 11)).opacity(0.7) | 128 | .font(.caption2).opacity(0.7) |
| 129 | #if DEBUG | ||
| 129 | TimelineView(.periodic(from: .now, by: 1)) { _ in | 130 | TimelineView(.periodic(from: .now, by: 1)) { _ in |
| 130 | Text(stats.summary(build: model.lastBuild)) | 131 | Text(stats.summary(build: model.lastBuild)) |
| 131 | .font(.system(size: 10).monospacedDigit()).opacity(0.7) | 132 | .font(.caption2.monospacedDigit()).opacity(0.7) |
| 132 | } | 133 | } |
| 134 | #endif | ||
| 133 | } | 135 | } |
| 134 | Spacer() | 136 | Spacer() |
| 135 | if pointer.available { | 137 | if pointer.available { |
| @@ -137,14 +139,14 @@ struct SkyScreen: View { | |||
| 137 | pointer.active ? pointer.stop() : pointer.start() | 139 | pointer.active ? pointer.stop() : pointer.start() |
| 138 | } label: { | 140 | } label: { |
| 139 | Image(systemName: pointer.active ? "scope" : "hand.draw") | 141 | Image(systemName: pointer.active ? "scope" : "hand.draw") |
| 140 | .font(.system(size: 17)) | 142 | .font(.body) |
| 141 | .frame(width: 44, height: 44) | 143 | .frame(width: 44, height: 44) |
| 142 | } | 144 | } |
| 143 | .accessibilityLabel(pointer.active ? "Stop following the phone" : "Point the phone at the sky") | 145 | .accessibilityLabel(pointer.active ? "Stop following the phone" : "Point the phone at the sky") |
| 144 | } | 146 | } |
| 145 | Button { showSettings = true } label: { | 147 | Button { showSettings = true } label: { |
| 146 | Image(systemName: "gearshape") | 148 | Image(systemName: "gearshape") |
| 147 | .font(.system(size: 17)) | 149 | .font(.body) |
| 148 | .frame(width: 44, height: 44) | 150 | .frame(width: 44, height: 44) |
| 149 | } | 151 | } |
| 150 | .accessibilityLabel("Settings") | 152 | .accessibilityLabel("Settings") |
| @@ -152,7 +154,7 @@ struct SkyScreen: View { | |||
| 152 | nightMode = night ? "off" : "on" | 154 | nightMode = night ? "off" : "on" |
| 153 | } label: { | 155 | } label: { |
| 154 | Image(systemName: night ? "eye.fill" : "eye") | 156 | Image(systemName: night ? "eye.fill" : "eye") |
| 155 | .font(.system(size: 17)) | 157 | .font(.body) |
| 156 | .frame(width: 44, height: 44) | 158 | .frame(width: 44, height: 44) |
| 157 | } | 159 | } |
| 158 | .accessibilityLabel(night ? "Turn off night mode" : "Turn on night mode") | 160 | .accessibilityLabel(night ? "Turn off night mode" : "Turn on night mode") |
| @@ -165,7 +167,7 @@ struct SkyScreen: View { | |||
| 165 | private func card(for object: SkyObject) -> some View { | 167 | private func card(for object: SkyObject) -> some View { |
| 166 | VStack(alignment: .leading, spacing: 8) { | 168 | VStack(alignment: .leading, spacing: 8) { |
| 167 | HStack { | 169 | HStack { |
| 168 | Text(title(for: object)).font(.system(size: 20, weight: .medium)) | 170 | Text(title(for: object)).font(.title3.weight(.medium)) |
| 169 | Spacer() | 171 | Spacer() |
| 170 | Button { selection = nil } label: { Image(systemName: "xmark").frame(width: 32, height: 32) } | 172 | Button { selection = nil } label: { Image(systemName: "xmark").frame(width: 32, height: 32) } |
| 171 | .accessibilityLabel("Close") | 173 | .accessibilityLabel("Close") |
| @@ -174,11 +176,11 @@ struct SkyScreen: View { | |||
| 174 | case .body: | 176 | case .body: |
| 175 | if let d = details { bodyFacts(d) } else { ProgressView().tint(ink) } | 177 | if let d = details { bodyFacts(d) } else { ProgressView().tint(ink) } |
| 176 | case .constellation(let id): | 178 | case .constellation(let id): |
| 177 | Text("Constellation · \(id)").font(.system(size: 13)).opacity(0.7) | 179 | Text("Constellation · \(id)").font(.footnote).opacity(0.7) |
| 178 | } | 180 | } |
| 179 | if let page = libraryPage(for: object) { | 181 | if let page = libraryPage(for: object) { |
| 180 | Button { libraryPage = page } label: { | 182 | Button { libraryPage = page } label: { |
| 181 | Label("Read more", systemImage: "book").font(.system(size: 13, weight: .medium)) | 183 | Label("Read more", systemImage: "book").font(.footnote.weight(.medium)) |
| 182 | } | 184 | } |
| 183 | .buttonStyle(.plain) | 185 | .buttonStyle(.plain) |
| 184 | .padding(.top, 4) | 186 | .padding(.top, 4) |
| @@ -223,7 +225,7 @@ struct SkyScreen: View { | |||
| 223 | Text(row.0).opacity(0.7) | 225 | Text(row.0).opacity(0.7) |
| 224 | Text(row.1).monospacedDigit() | 226 | Text(row.1).monospacedDigit() |
| 225 | } | 227 | } |
| 226 | .font(.system(size: 13)) | 228 | .font(.footnote) |
| 227 | } | 229 | } |
| 228 | } | 230 | } |
| 229 | } | 231 | } |
App/Sources/SunScreen.swift +15 −15
| @@ -19,7 +19,7 @@ struct SunScreen: View { | |||
| 19 | var body: some View { | 19 | var body: some View { |
| 20 | ScrollView { | 20 | ScrollView { |
| 21 | VStack(alignment: .leading, spacing: 0) { | 21 | VStack(alignment: .leading, spacing: 0) { |
| 22 | Text("Sun").font(.system(size: 28, weight: .medium)) | 22 | Text("Sun").font(.title.weight(.medium)) |
| 23 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 8).padding(.bottom, 16) | 23 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 8).padding(.bottom, 16) |
| 24 | 24 | ||
| 25 | image | 25 | image |
| @@ -28,17 +28,17 @@ struct SunScreen: View { | |||
| 28 | } | 28 | } |
| 29 | .pickerStyle(.segmented) | 29 | .pickerStyle(.segmented) |
| 30 | .padding(.top, 12) | 30 | .padding(.top, 12) |
| 31 | Text(wavelength.caption).font(.system(size: 13)).opacity(0.75).padding(.top, 8) | 31 | Text(wavelength.caption).font(.footnote).opacity(0.75).padding(.top, 8) |
| 32 | Text(SolarImage.credit).font(.system(size: 10)).opacity(0.5).padding(.top, 4) | 32 | Text(SolarImage.credit).font(.caption2).opacity(0.5).padding(.top, 4) |
| 33 | 33 | ||
| 34 | section("Aurora") { auroraMap } | 34 | section("Aurora") { auroraMap } |
| 35 | section("Solar flares, last 24 h") { flares } | 35 | section("Solar flares, last 24 h") { flares } |
| 36 | section("Geomagnetic activity (Kp)") { kpChart } | 36 | section("Geomagnetic activity (Kp)") { kpChart } |
| 37 | 37 | ||
| 38 | if failed { | 38 | if failed { |
| 39 | Text("Couldn't load space weather. Pull to retry.").font(.system(size: 13)).foregroundStyle(accent).padding(.top, 12) | 39 | Text("Couldn't load space weather. Pull to retry.").font(.footnote).foregroundStyle(accent).padding(.top, 12) |
| 40 | } | 40 | } |
| 41 | Text("Space weather data: NOAA Space Weather Prediction Center. Coastlines: Natural Earth.").font(.system(size: 10)).opacity(0.5).padding(.vertical, 16) | 41 | Text("Space weather data: NOAA Space Weather Prediction Center. Coastlines: Natural Earth.").font(.caption2).opacity(0.5).padding(.vertical, 16) |
| 42 | } | 42 | } |
| 43 | .padding(.horizontal, 20) | 43 | .padding(.horizontal, 20) |
| 44 | } | 44 | } |
| @@ -64,7 +64,7 @@ struct SunScreen: View { | |||
| 64 | AsyncImage(url: wavelength.url(size: 1024)) { phase in | 64 | AsyncImage(url: wavelength.url(size: 1024)) { phase in |
| 65 | switch phase { | 65 | switch phase { |
| 66 | case .success(let img): img.resizable().scaledToFit() | 66 | case .success(let img): img.resizable().scaledToFit() |
| 67 | case .failure: Color.black.overlay(Text("Image unavailable").font(.system(size: 13)).opacity(0.6)) | 67 | case .failure: Color.black.overlay(Text("Image unavailable").font(.footnote).opacity(0.6)) |
| 68 | default: Color.black.overlay(ProgressView().tint(ink)) | 68 | default: Color.black.overlay(ProgressView().tint(ink)) |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| @@ -75,7 +75,7 @@ struct SunScreen: View { | |||
| 75 | 75 | ||
| 76 | private func section(_ title: String, @ViewBuilder content: () -> some View) -> some View { | 76 | private func section(_ title: String, @ViewBuilder content: () -> some View) -> some View { |
| 77 | VStack(alignment: .leading, spacing: 10) { | 77 | VStack(alignment: .leading, spacing: 10) { |
| 78 | Text(title).font(.system(size: 11, weight: .medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) | 78 | Text(title).font(.caption2.weight(.medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) |
| 79 | content() | 79 | content() |
| 80 | } | 80 | } |
| 81 | .padding(.top, 24) | 81 | .padding(.top, 24) |
| @@ -94,9 +94,9 @@ struct SunScreen: View { | |||
| 94 | .accessibilityElement() | 94 | .accessibilityElement() |
| 95 | .accessibilityLabel(auroraDescription(ovation)) | 95 | .accessibilityLabel(auroraDescription(ovation)) |
| 96 | Text("Chance of visible aurora overhead, OVATION model, for \(ovation.forecastTime.formatted(date: .omitted, time: .shortened)). Brighter green is more likely.") | 96 | Text("Chance of visible aurora overhead, OVATION model, for \(ovation.forecastTime.formatted(date: .omitted, time: .shortened)). Brighter green is more likely.") |
| 97 | .font(.system(size: 11)).opacity(0.6) | 97 | .font(.caption2).opacity(0.6) |
| 98 | } else { | 98 | } else { |
| 99 | Text("Loading").font(.system(size: 13)).opacity(0.6) | 99 | Text("Loading").font(.footnote).opacity(0.6) |
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| @@ -127,7 +127,7 @@ struct SunScreen: View { | |||
| 127 | .foregroundStyle(c.0 == "C" ? ink.opacity(0.25) : accent.opacity(0.6)) | 127 | .foregroundStyle(c.0 == "C" ? ink.opacity(0.25) : accent.opacity(0.6)) |
| 128 | .lineStyle(StrokeStyle(lineWidth: 0.5, dash: [3, 3])) | 128 | .lineStyle(StrokeStyle(lineWidth: 0.5, dash: [3, 3])) |
| 129 | .annotation(position: .top, alignment: .leading) { | 129 | .annotation(position: .top, alignment: .leading) { |
| 130 | Text(c.0).font(.system(size: 10)).opacity(0.7) | 130 | Text(c.0).font(.caption2).opacity(0.7) |
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | } | 133 | } |
| @@ -141,14 +141,14 @@ struct SunScreen: View { | |||
| 141 | } | 141 | } |
| 142 | .frame(height: 160) | 142 | .frame(height: 160) |
| 143 | } else { | 143 | } else { |
| 144 | Text("Loading").font(.system(size: 13)).opacity(0.6) | 144 | Text("Loading").font(.footnote).opacity(0.6) |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | @ViewBuilder | 148 | @ViewBuilder |
| 149 | private var kpChart: some View { | 149 | private var kpChart: some View { |
| 150 | if kp.isEmpty { | 150 | if kp.isEmpty { |
| 151 | Text("Loading").font(.system(size: 13)).opacity(0.6) | 151 | Text("Loading").font(.footnote).opacity(0.6) |
| 152 | } else { | 152 | } else { |
| 153 | Chart(kp) { bar in | 153 | Chart(kp) { bar in |
| 154 | BarMark(x: .value("Start", bar.start, unit: .hour), y: .value("Kp", bar.kp), width: .ratio(0.8)) | 154 | BarMark(x: .value("Start", bar.start, unit: .hour), y: .value("Kp", bar.kp), width: .ratio(0.8)) |
| @@ -169,14 +169,14 @@ struct SunScreen: View { | |||
| 169 | } | 169 | } |
| 170 | .frame(height: 140) | 170 | .frame(height: 140) |
| 171 | Text("Solid: observed. Faint: forecast. Red: storm level (Kp 5 or more).") | 171 | Text("Solid: observed. Faint: forecast. Red: storm level (Kp 5 or more).") |
| 172 | .font(.system(size: 11)).opacity(0.6) | 172 | .font(.caption2).opacity(0.6) |
| 173 | } | 173 | } |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | private func stat(_ label: String, _ value: String) -> some View { | 176 | private func stat(_ label: String, _ value: String) -> some View { |
| 177 | VStack(alignment: .leading, spacing: 2) { | 177 | VStack(alignment: .leading, spacing: 2) { |
| 178 | Text(label).font(.system(size: 10)).opacity(0.6) | 178 | Text(label).font(.caption2).opacity(0.6) |
| 179 | Text(value).font(.system(size: 20, weight: .medium).monospacedDigit()) | 179 | Text(value).font(.title3.weight(.medium).monospacedDigit()) |
| 180 | } | 180 | } |
| 181 | } | 181 | } |
| 182 | } | 182 | } |
App/Sources/SystemScreen.swift +8 −8
| @@ -22,7 +22,7 @@ struct SystemScreen: View { | |||
| 22 | var body: some View { | 22 | var body: some View { |
| 23 | ScrollView { | 23 | ScrollView { |
| 24 | VStack(alignment: .leading, spacing: 0) { | 24 | VStack(alignment: .leading, spacing: 0) { |
| 25 | Text("Solar system").font(.system(size: 28, weight: .medium)) | 25 | Text("Solar system").font(.title.weight(.medium)) |
| 26 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 8).padding(.bottom, 16) | 26 | Rectangle().fill(accent).frame(width: 48, height: 5).padding(.top, 8).padding(.bottom, 16) |
| 27 | 27 | ||
| 28 | OrreryView(date: date, ink: ink, accent: accent) | 28 | OrreryView(date: date, ink: ink, accent: accent) |
| @@ -35,17 +35,17 @@ struct SystemScreen: View { | |||
| 35 | } | 35 | } |
| 36 | .accessibilityLabel(playing ? "Pause" : "Play") | 36 | .accessibilityLabel(playing ? "Pause" : "Play") |
| 37 | Text(date.formatted(.dateTime.year().month(.abbreviated))) | 37 | Text(date.formatted(.dateTime.year().month(.abbreviated))) |
| 38 | .font(.system(size: 15, weight: .medium).monospacedDigit()) | 38 | .font(.subheadline.weight(.medium).monospacedDigit()) |
| 39 | .frame(width: 80, alignment: .leading) | 39 | .frame(width: 80, alignment: .leading) |
| 40 | Slider(value: $offsetDays, in: range).tint(ink) | 40 | Slider(value: $offsetDays, in: range).tint(ink) |
| 41 | Button("Today") { playing = false; offsetDays = 0 } | 41 | Button("Today") { playing = false; offsetDays = 0 } |
| 42 | .font(.system(size: 13, weight: .medium)) | 42 | .font(.footnote.weight(.medium)) |
| 43 | .opacity(abs(offsetDays) < 1 ? 0.4 : 1) | 43 | .opacity(abs(offsetDays) < 1 ? 0.4 : 1) |
| 44 | } | 44 | } |
| 45 | .padding(.top, 12) | 45 | .padding(.top, 12) |
| 46 | 46 | ||
| 47 | Text("Distances beyond 1 AU are drawn on a logarithmic scale. Rings: planet orbits, then 50, 100 and 200 AU.") | 47 | Text("Distances beyond 1 AU are drawn on a logarithmic scale. Rings: planet orbits, then 50, 100 and 200 AU.") |
| 48 | .font(.system(size: 11)).opacity(0.6).padding(.top, 8) | 48 | .font(.caption2).opacity(0.6).padding(.top, 8) |
| 49 | 49 | ||
| 50 | section("Spacecraft") { | 50 | section("Spacecraft") { |
| 51 | Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 6) { | 51 | Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 6) { |
| @@ -54,7 +54,7 @@ struct SystemScreen: View { | |||
| 54 | Text("From Sun").opacity(0.6) | 54 | Text("From Sun").opacity(0.6) |
| 55 | Text("Light time").opacity(0.6) | 55 | Text("Light time").opacity(0.6) |
| 56 | } | 56 | } |
| 57 | .font(.system(size: 11)) | 57 | .font(.caption2) |
| 58 | ForEach(Spacecraft.all) { craft in | 58 | ForEach(Spacecraft.all) { craft in |
| 59 | GridRow { | 59 | GridRow { |
| 60 | if let page = Library.page(spacecraft: craft.name) { | 60 | if let page = Library.page(spacecraft: craft.name) { |
| @@ -70,12 +70,12 @@ struct SystemScreen: View { | |||
| 70 | Text("") | 70 | Text("") |
| 71 | } | 71 | } |
| 72 | } | 72 | } |
| 73 | .font(.system(size: 14)) | 73 | .font(.subheadline) |
| 74 | } | 74 | } |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| 77 | Text("Spacecraft positions: NASA/JPL Horizons. Pioneer 10 and 11 positions after contact was lost are predictions.") | 77 | Text("Spacecraft positions: NASA/JPL Horizons. Pioneer 10 and 11 positions after contact was lost are predictions.") |
| 78 | .font(.system(size: 10)).opacity(0.5).padding(.vertical, 16) | 78 | .font(.caption2).opacity(0.5).padding(.vertical, 16) |
| 79 | } | 79 | } |
| 80 | .padding(.horizontal, 20) | 80 | .padding(.horizontal, 20) |
| 81 | } | 81 | } |
| @@ -102,7 +102,7 @@ struct SystemScreen: View { | |||
| 102 | 102 | ||
| 103 | private func section(_ title: String, @ViewBuilder content: () -> some View) -> some View { | 103 | private func section(_ title: String, @ViewBuilder content: () -> some View) -> some View { |
| 104 | VStack(alignment: .leading, spacing: 10) { | 104 | VStack(alignment: .leading, spacing: 10) { |
| 105 | Text(title).font(.system(size: 11, weight: .medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) | 105 | Text(title).font(.caption2.weight(.medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) |
| 106 | content() | 106 | content() |
| 107 | } | 107 | } |
| 108 | .padding(.top, 24) | 108 | .padding(.top, 24) |
App/Sources/TodaySheet.swift +8 −8
| @@ -18,7 +18,7 @@ struct TodaySheet: View { | |||
| 18 | } | 18 | } |
| 19 | section("Space weather") { weather } | 19 | section("Space weather") { weather } |
| 20 | Text("Space weather data: NOAA Space Weather Prediction Center.") | 20 | Text("Space weather data: NOAA Space Weather Prediction Center.") |
| 21 | .font(.system(size: 11)).opacity(0.5).padding(.top, 8) | 21 | .font(.caption2).opacity(0.5).padding(.top, 8) |
| 22 | } | 22 | } |
| 23 | .padding(.horizontal, 20) | 23 | .padding(.horizontal, 20) |
| 24 | .padding(.top, 18) | 24 | .padding(.top, 18) |
| @@ -29,7 +29,7 @@ struct TodaySheet: View { | |||
| 29 | 29 | ||
| 30 | private func section(_ title: String, @ViewBuilder content: () -> some View) -> some View { | 30 | private func section(_ title: String, @ViewBuilder content: () -> some View) -> some View { |
| 31 | VStack(alignment: .leading, spacing: 8) { | 31 | VStack(alignment: .leading, spacing: 8) { |
| 32 | Text(title).font(.system(size: 11, weight: .medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) | 32 | Text(title).font(.caption2.weight(.medium)).textCase(.uppercase).tracking(0.8).opacity(0.6) |
| 33 | content() | 33 | content() |
| 34 | } | 34 | } |
| 35 | .frame(maxWidth: .infinity, alignment: .leading) | 35 | .frame(maxWidth: .infinity, alignment: .leading) |
| @@ -86,7 +86,7 @@ struct TodaySheet: View { | |||
| 86 | ("Updated", time(w.observedAt)), | 86 | ("Updated", time(w.observedAt)), |
| 87 | ]) | 87 | ]) |
| 88 | } else { | 88 | } else { |
| 89 | Text("Loading").font(.system(size: 13)).opacity(0.6) | 89 | Text("Loading").font(.footnote).opacity(0.6) |
| 90 | } | 90 | } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| @@ -97,7 +97,7 @@ struct TodaySheet: View { | |||
| 97 | Text(item.0).opacity(0.7) | 97 | Text(item.0).opacity(0.7) |
| 98 | Text(item.1).monospacedDigit() | 98 | Text(item.1).monospacedDigit() |
| 99 | } | 99 | } |
| 100 | .font(.system(size: 14)) | 100 | .font(.subheadline) |
| 101 | } | 101 | } |
| 102 | } | 102 | } |
| 103 | } | 103 | } |
| @@ -121,9 +121,9 @@ struct TodayBar: View { | |||
| 121 | scrubber | 121 | scrubber |
| 122 | Button(action: onExpand) { | 122 | Button(action: onExpand) { |
| 123 | HStack { | 123 | HStack { |
| 124 | Text(summary).font(.system(size: 13)).opacity(0.75).lineLimit(1) | 124 | Text(summary).font(.footnote).opacity(0.75).lineLimit(2) |
| 125 | Spacer() | 125 | Spacer() |
| 126 | Image(systemName: "chevron.up").font(.system(size: 12, weight: .medium)).opacity(0.6) | 126 | Image(systemName: "chevron.up").font(.caption.weight(.medium)).opacity(0.6) |
| 127 | } | 127 | } |
| 128 | } | 128 | } |
| 129 | .buttonStyle(.plain) | 129 | .buttonStyle(.plain) |
| @@ -154,11 +154,11 @@ struct TodayBar: View { | |||
| 154 | private var scrubber: some View { | 154 | private var scrubber: some View { |
| 155 | HStack(spacing: 12) { | 155 | HStack(spacing: 12) { |
| 156 | Text(model.displayedDate.formatted(date: .omitted, time: .shortened)) | 156 | Text(model.displayedDate.formatted(date: .omitted, time: .shortened)) |
| 157 | .font(.system(size: 13).monospacedDigit()) | 157 | .font(.footnote.monospacedDigit()) |
| 158 | .frame(width: 70, alignment: .leading) | 158 | .frame(width: 70, alignment: .leading) |
| 159 | Slider(value: $model.offsetHours, in: -12...12, step: 0.25).tint(ink) | 159 | Slider(value: $model.offsetHours, in: -12...12, step: 0.25).tint(ink) |
| 160 | Button("Now") { model.offsetHours = 0 } | 160 | Button("Now") { model.offsetHours = 0 } |
| 161 | .font(.system(size: 13, weight: .medium)) | 161 | .font(.footnote.weight(.medium)) |
| 162 | .opacity(model.offsetHours == 0 ? 0.4 : 1) | 162 | .opacity(model.offsetHours == 0 ? 0.4 : 1) |
| 163 | } | 163 | } |
| 164 | } | 164 | } |