From ffbc3fe7f87ae8f1afc0aef8d9ad5378ec2eb8a5 Mon Sep 17 00:00:00 2001 From: sirily11 <32106111+sirily11@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:35:48 +0800 Subject: [PATCH] fix: release configuration --- .../AccentColor.colorset/Contents.json | 27 ++ RxNote/RxNote/Config/Release.xcconfig | 2 +- RxNote/RxNote/RxNote.entitlements | 14 +- .../RxNote/Views/Notes/NoteEditorView.swift | 296 +++++++++++------- RxNote/RxNote/Views/Notes/NoteListView.swift | 63 ++-- .../RxNote/Views/Notes/WiFiActionButton.swift | 19 +- .../RxNote/Views/Settings/WebPageView.swift | 59 +++- RxNote/RxNoteClips/RxNoteClips.entitlements | 4 +- backend/app/(legal)/layout.tsx | 5 +- backend/app/(legal)/loading.tsx | 57 ++++ backend/app/(legal)/privacy/page.mdx | 4 +- backend/app/(legal)/terms/page.mdx | 2 +- backend/app/globals.css | 14 + backend/app/layout.tsx | 10 +- backend/app/providers.tsx | 15 +- backend/components/theme-toggle.tsx | 21 ++ backend/mdx-components.tsx | 5 +- 17 files changed, 443 insertions(+), 174 deletions(-) create mode 100644 backend/app/(legal)/loading.tsx create mode 100644 backend/components/theme-toggle.tsx diff --git a/RxNote/RxNote/Assets.xcassets/AccentColor.colorset/Contents.json b/RxNote/RxNote/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897..648780f 100644 --- a/RxNote/RxNote/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/RxNote/RxNote/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,33 @@ { "colors" : [ { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.820", + "green" : "0.220", + "red" : "0.506" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.780", + "green" : "0.520", + "red" : "0.720" + } + }, "idiom" : "universal" } ], diff --git a/RxNote/RxNote/Config/Release.xcconfig b/RxNote/RxNote/Config/Release.xcconfig index 78215e1..72a5c3e 100644 --- a/RxNote/RxNote/Config/Release.xcconfig +++ b/RxNote/RxNote/Config/Release.xcconfig @@ -6,7 +6,7 @@ // API Configuration - Production // Update this to your production API URL -API_BASE_URL = https:/$()/note.rxlab.app +API_BASE_URL = https:/$()/rxnote.rxlab.app // OAuth Configuration - Production AUTH_ISSUER = https:/$()/auth.rxlab.app diff --git a/RxNote/RxNote/RxNote.entitlements b/RxNote/RxNote/RxNote.entitlements index 3956b8f..e9464b5 100644 --- a/RxNote/RxNote/RxNote.entitlements +++ b/RxNote/RxNote/RxNote.entitlements @@ -6,17 +6,17 @@ development com.apple.developer.associated-domains - applinks:note.rxlab.app - appclips:note.rxlab.app - webcredentials:note.rxlab.app + applinks:rxnote.rxlab.app + appclips:rxnote.rxlab.app + webcredentials:rxnote.rxlab.app + com.apple.developer.networking.HotspotConfiguration + + com.apple.developer.networking.wifi-info + com.apple.developer.nfc.readersession.formats TAG - com.apple.developer.networking.wifi-info - - com.apple.developer.networking.HotspotConfiguration - diff --git a/RxNote/RxNote/Views/Notes/NoteEditorView.swift b/RxNote/RxNote/Views/Notes/NoteEditorView.swift index 99e96d0..d6f26d7 100644 --- a/RxNote/RxNote/Views/Notes/NoteEditorView.swift +++ b/RxNote/RxNote/Views/Notes/NoteEditorView.swift @@ -10,6 +10,31 @@ import PhotosUI import RxNoteCore import SwiftUI +// MARK: - App Theme Color + +extension Color { + static var appAccent: Color { + Color(light: Color(red: 0.506, green: 0.220, blue: 0.820), + dark: Color(red: 0.720, green: 0.520, blue: 0.780)) + } + + init(light: Color, dark: Color) { + #if os(iOS) + self.init(uiColor: UIColor { traitCollection in + traitCollection.userInterfaceStyle == .dark + ? UIColor(dark) + : UIColor(light) + }) + #else + self.init(nsColor: NSColor(name: nil) { appearance in + appearance.bestMatch(from: [.darkAqua, .vibrantDark]) != nil + ? NSColor(dark) + : NSColor(light) + }) + #endif + } +} + struct NoteEditorView: View { let mode: NoteEditorMode let onSave: ((Note) -> Void)? @@ -48,13 +73,14 @@ struct NoteEditorView: View { Task { await handlePhotoSelection(items) } selectedPhotoItems = [] } - #if os(iOS) + .scrollDismissesKeyboard(.interactively) + #if os(iOS) .sheet(isPresented: $showCamera) { CameraPickerView { image in Task { await handleCameraCapture(image) } } } - #endif + #endif .sheet(isPresented: $showLocationPicker) { LocationPickerView( latitude: viewModel.latitude, @@ -85,15 +111,15 @@ struct NoteEditorView: View { Text(error.localizedDescription) } } - #if os(iOS) + #if os(iOS) .fullScreenCover(item: $fullscreenImageURL) { url in FullscreenImageView(imageURL: url) } - #else + #else .sheet(item: $fullscreenImageURL) { url in FullscreenImageView(imageURL: url) } - #endif + #endif } // MARK: - Navigation Wrapper @@ -116,108 +142,108 @@ struct NoteEditorView: View { private var editorWithToolbar: some View { editorContent - #if os(iOS) - .background(Color(.systemBackground)) - .navigationBarTitleDisplayMode(.inline) - #endif - .toolbar { - if !viewModel.isReadOnly { - ToolbarItem(placement: .navigation) { - Button { - if let onCancel { - onCancel() - } else { - dismiss() - } - } label: { - Label("Cancel", systemImage: "xmark") + #if os(iOS) + .background(Color(.systemBackground)) + .navigationBarTitleDisplayMode(.inline) + #endif + .toolbar { + if !viewModel.isReadOnly { + ToolbarItem(placement: .navigation) { + Button { + if let onCancel { + onCancel() + } else { + dismiss() } + } label: { + Label("Cancel", systemImage: "xmark") } - #if os(iOS) - ToolbarItemGroup(placement: .bottomBar) { - Spacer() + } + #if os(iOS) + ToolbarItemGroup(placement: .bottomBar) { + Spacer() - PhotosPicker( - selection: $selectedPhotoItems, - maxSelectionCount: 5, - matching: .images - ) { - Image(systemName: "photo.on.rectangle") - } + PhotosPicker( + selection: $selectedPhotoItems, + maxSelectionCount: 5, + matching: .images + ) { + Image(systemName: "photo.on.rectangle") + } - Button { showCamera = true } label: { - Image(systemName: "camera") - } + Button { showCamera = true } label: { + Image(systemName: "camera") + } - Button { showLocationPicker = true } label: { - Image(systemName: viewModel.latitude != nil ? "location.fill" : "location") - } + Button { showLocationPicker = true } label: { + Image(systemName: viewModel.latitude != nil ? "location.fill" : "location") + } - Button { actionSheetMode = .create } label: { - Image(systemName: "link.badge.plus") - } + Button { actionSheetMode = .create } label: { + Image(systemName: "link.badge.plus") + } - Spacer() + Spacer() + } + #else + ToolbarItemGroup(placement: .secondaryAction) { + PhotosPicker( + selection: $selectedPhotoItems, + maxSelectionCount: 5, + matching: .images + ) { + Label("Add Photos", systemImage: "photo.on.rectangle") } - #else - ToolbarItemGroup(placement: .secondaryAction) { - PhotosPicker( - selection: $selectedPhotoItems, - maxSelectionCount: 5, - matching: .images - ) { - Label("Add Photos", systemImage: "photo.on.rectangle") - } - Button { showLocationPicker = true } label: { - Label("Add Location", systemImage: viewModel.latitude != nil ? "location.fill" : "location") - } + Button { showLocationPicker = true } label: { + Label("Add Location", systemImage: viewModel.latitude != nil ? "location.fill" : "location") + } - Button { actionSheetMode = .create } label: { - Label("Add Action", systemImage: "link.badge.plus") - } + Button { actionSheetMode = .create } label: { + Label("Add Action", systemImage: "link.badge.plus") } - #endif } + #endif + } - ToolbarItemGroup(placement: .primaryAction) { - if !viewModel.isReadOnly { - Button { - showVisibilityPicker = true - } label: { - Label(viewModel.visibility.displayName, systemImage: viewModel.visibility.systemImage) - .font(.subheadline) - .foregroundStyle(.secondary) - } - .popover(isPresented: $showVisibilityPicker) { - visibilityPicker - } + ToolbarItemGroup(placement: .primaryAction) { + if !viewModel.isReadOnly { + Button { + showVisibilityPicker = true + } label: { + Label(viewModel.visibility.displayName, systemImage: viewModel.visibility.systemImage) + .font(.subheadline) + .foregroundStyle(.secondary) + } + .popover(isPresented: $showVisibilityPicker) { + visibilityPicker } + } - if viewModel.isReadOnly { - // Only show edit button if onEdit callback is provided - if let onEdit { - Button { - onEdit() - } label: { - Image(systemName: "pencil") - .font(.title3.weight(.medium)) - } - .accessibilityIdentifier("note-detail-edit-button") - } - } else if viewModel.isSaving { - ProgressView() - } else { + if viewModel.isReadOnly { + // Only show edit button if onEdit callback is provided + if let onEdit { Button { - Task { await saveNote() } + onEdit() } label: { - Image(systemName: "checkmark") + Image(systemName: "pencil") + .font(.title3.weight(.medium)) } - .accessibilityIdentifier("note-save-button") - .disabled(!viewModel.canSave || viewModel.hasUploadsInProgress) + .accessibilityIdentifier("note-detail-edit-button") } + } else if viewModel.isSaving { + ProgressView() + } else { + Button { + Task { await saveNote() } + } label: { + Image(systemName: "checkmark") + } + .accessibilityIdentifier("note-save-button") + .disabled(!viewModel.canSave || viewModel.hasUploadsInProgress) } } + } } // MARK: - Visibility Picker @@ -234,7 +260,7 @@ struct NoteEditorView: View { Spacer() if viewModel.visibility == vis { Image(systemName: "checkmark") - .foregroundStyle(.purple) + .foregroundStyle(Color.appAccent) } } .padding(.horizontal, 16) @@ -373,7 +399,7 @@ struct NoteEditorView: View { span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) ))) { Marker("", coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude)) - .tint(.purple) + .tint(Color.appAccent) } .frame(height: 150) .clipShape(RoundedRectangle(cornerRadius: 12)) @@ -482,32 +508,36 @@ struct NoteEditorView: View { // MARK: - Actions Section private var actionsSection: some View { - VStack(alignment: .leading, spacing: 6) { + VStack(alignment: .leading, spacing: 12) { ForEach(Array(viewModel.actions.enumerated()), id: \.offset) { index, action in HStack { actionLabel(action) + .foregroundStyle(Color.appAccent) Spacer() - if !viewModel.isReadOnly { - Button { - actionSheetMode = .edit(index: index, action: viewModel.actions[index]) - } label: { - Image(systemName: "pencil") - .font(.caption) - .foregroundStyle(.secondary) - } - Button { - viewModel.removeAction(at: index) - } label: { - Image(systemName: "xmark.circle.fill") - .font(.caption) - .foregroundStyle(.secondary) - } + Button { + actionSheetMode = .edit(index: index, action: viewModel.actions[index]) + } label: { + Image(systemName: "pencil") + .font(.caption.weight(.semibold)) + .foregroundStyle(.secondary) + } + Button { + viewModel.removeAction(at: index) + } label: { + Image(systemName: "xmark.circle.fill") + .font(.callout) + .symbolRenderingMode(.palette) + .foregroundStyle(.white, .black.opacity(0.6)) } } .padding(.horizontal, 16) - .padding(.vertical, 6) - .background(Color(.secondarySystemFill)) - .clipShape(RoundedRectangle(cornerRadius: 8)) + .padding(.vertical, 14) + #if os(iOS) + .background(Color(.secondarySystemBackground)) + #else + .background(Color(NSColor.controlBackgroundColor)) + #endif + .clipShape(RoundedRectangle(cornerRadius: 12)) } } .padding(.horizontal, 16) @@ -518,10 +548,10 @@ struct NoteEditorView: View { switch action { case let .url(urlAction): Label(urlAction.label, systemImage: "link") - .font(.subheadline) + .font(.body.weight(.medium)) case let .wifi(wifiAction): Label(wifiAction.ssid, systemImage: "wifi") - .font(.subheadline) + .font(.body.weight(.medium)) } } @@ -557,14 +587,14 @@ struct NoteEditorView: View { .padding(.horizontal, 16) .padding(.vertical, 14) #if os(iOS) - .background(Color(.secondarySystemBackground)) + .background(Color(.secondarySystemBackground)) #else - .background(Color(NSColor.controlBackgroundColor)) + .background(Color(NSColor.controlBackgroundColor)) #endif - .clipShape(RoundedRectangle(cornerRadius: 12)) + .clipShape(RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) - .foregroundStyle(.purple) + .foregroundStyle(Color.appAccent) } case let .wifi(wifiAction): WiFiActionButton(wifiAction: wifiAction, connectionState: $wifiConnectionState) @@ -576,7 +606,11 @@ struct NoteEditorView: View { private func saveNote() async { if let note = await viewModel.save() { onSave?(note) - dismiss() + // Only dismiss if not in inline mode (detail view) + // When onCancel is provided, the parent view handles navigation + if !isInline { + dismiss() + } } } @@ -654,3 +688,37 @@ extension String: @retroactive Identifiable { ) NoteEditorView(mode: .view(noteId: 1, existing: sampleNote)) } +#Preview("Edit Mode") { + let sampleNote = NoteDetail( + id: 1, + userId: "user-1", + _type: .regular_hyphen_text_hyphen_note, + title: "Meeting Room WiFi", + note: "Connect to the guest network using the credentials below.", + images: [], + audios: [], + videos: [], + latitude: 37.7749, + longitude: -122.4194, + actions: [ + .url(.init( + _type: .url, + label: "Company Website", + url: "https://example.com" + )), + .wifi(.init( + _type: .wifi, + ssid: "GuestNetwork", + password: "welcome123", + encryption: .WPA + )) + ], + visibility: ._public, + previewUrl: "https://example.com/preview/1", + createdAt: Date(), + updatedAt: Date(), + whitelist: [] + ) + NoteEditorView(mode: .edit(noteId: 1, existing: sampleNote)) +} + diff --git a/RxNote/RxNote/Views/Notes/NoteListView.swift b/RxNote/RxNote/Views/Notes/NoteListView.swift index 2aedf64..2673424 100644 --- a/RxNote/RxNote/Views/Notes/NoteListView.swift +++ b/RxNote/RxNote/Views/Notes/NoteListView.swift @@ -41,31 +41,6 @@ struct NoteListView: View { .accessibilityIdentifier("add-note-button") } } - #if os(iOS) - .fullScreenCover(isPresented: $showNoteEditor, onDismiss: { - if let noteId = pendingNavigationNoteId { - pendingNavigationNoteId = nil - navigationManager.navigateToNote(id: noteId) - } - }) { - NoteEditorView(mode: .create) { note in - Task { await viewModel.fetchNotes() } - pendingNavigationNoteId = note.id - } - } - #else - .sheet(isPresented: $showNoteEditor, onDismiss: { - if let noteId = pendingNavigationNoteId { - pendingNavigationNoteId = nil - navigationManager.navigateToNote(id: noteId) - } - }) { - NoteEditorView(mode: .create) { note in - Task { await viewModel.fetchNotes() } - pendingNavigationNoteId = note.id - } - } - #endif .alert( "Error", isPresented: $showingErrorAlert, @@ -88,6 +63,31 @@ struct NoteListView: View { .refreshable { await viewModel.fetchNotes() } + #if os(iOS) + .fullScreenCover(isPresented: $showNoteEditor, onDismiss: { + if let noteId = pendingNavigationNoteId { + pendingNavigationNoteId = nil + navigationManager.navigateToNote(id: noteId) + } + }) { + NoteEditorView(mode: .create) { note in + Task { await viewModel.fetchNotes() } + pendingNavigationNoteId = note.id + } + } + #else + .sheet(isPresented: $showNoteEditor, onDismiss: { + if let noteId = pendingNavigationNoteId { + pendingNavigationNoteId = nil + navigationManager.navigateToNote(id: noteId) + } + }) { + NoteEditorView(mode: .create) { note in + Task { await viewModel.fetchNotes() } + pendingNavigationNoteId = note.id + } + } + #endif } private var notesList: some View { @@ -97,14 +97,14 @@ struct NoteListView: View { NoteRow(note: note) } .accessibilityIdentifier("note-row-\(note.id)") - .onAppear { - // Load more when reaching near the end - if note.id == viewModel.notes.last?.id, viewModel.hasNextPage { - Task { - await viewModel.loadMore() - } + .onAppear { + // Load more when reaching near the end + if note.id == viewModel.notes.last?.id, viewModel.hasNextPage { + Task { + await viewModel.loadMore() } } + } } .onDelete { indexSet in Task { @@ -171,7 +171,6 @@ private struct NoteRow: View { } } - #Preview { NavigationStack { NoteListView() diff --git a/RxNote/RxNote/Views/Notes/WiFiActionButton.swift b/RxNote/RxNote/Views/Notes/WiFiActionButton.swift index 75de1ba..4b2e431 100644 --- a/RxNote/RxNote/Views/Notes/WiFiActionButton.swift +++ b/RxNote/RxNote/Views/Notes/WiFiActionButton.swift @@ -62,13 +62,30 @@ struct WiFiActionButton: View { .clipShape(RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) - .foregroundStyle(isConnecting ? Color.secondary : Color.purple) + .foregroundStyle(titleColor) .disabled(isConnecting) } private var isConnecting: Bool { connectionState.isConnecting(ssid: wifiAction.ssid) } + + private var isConnected: Bool { + if case .connected(let connectedSSID) = connectionState { + return connectedSSID == wifiAction.ssid + } + return false + } + + private var titleColor: Color { + if isConnecting { + return .secondary + } else if isConnected { + return .green + } else { + return Color.appAccent + } + } @ViewBuilder private var statusIcon: some View { diff --git a/RxNote/RxNote/Views/Settings/WebPageView.swift b/RxNote/RxNote/Views/Settings/WebPageView.swift index d0fed3e..ccb1a92 100644 --- a/RxNote/RxNote/Views/Settings/WebPageView.swift +++ b/RxNote/RxNote/Views/Settings/WebPageView.swift @@ -15,9 +15,10 @@ struct WebPageView: View { var body: some View { WebViewRepresentable(url: page.url) .navigationTitle(page.title) - #if os(iOS) - .navigationBarTitleDisplayMode(.inline) - #endif + #if os(iOS) + .toolbar(.hidden, for: .tabBar) + .navigationBarTitleDisplayMode(.inline) + #endif .ignoresSafeArea(edges: .bottom) } } @@ -27,9 +28,35 @@ struct WebPageView: View { #if os(iOS) private struct WebViewRepresentable: UIViewRepresentable { let url: URL + @Environment(\.colorScheme) private var colorScheme func makeUIView(context: Context) -> WKWebView { - let webView = WKWebView() + let configuration = WKWebViewConfiguration() + let userContentController = WKUserContentController() + + // Inject CSS to support dark mode background + let darkModeCSS = """ + @media (prefers-color-scheme: dark) { + html, body { + background-color: #000000 !important; + color-scheme: dark; + } + } + """ + let cssScript = WKUserScript( + source: + "var style = document.createElement('style'); style.innerHTML = '\(darkModeCSS.replacingOccurrences(of: "\n", with: " "))'; document.head.appendChild(style);", + injectionTime: .atDocumentEnd, + forMainFrameOnly: true + ) + userContentController.addUserScript(cssScript) + configuration.userContentController = userContentController + + let webView = WKWebView(frame: .zero, configuration: configuration) + webView.isOpaque = false + webView.backgroundColor = .systemBackground + webView.scrollView.backgroundColor = .systemBackground + webView.underPageBackgroundColor = .systemBackground webView.load(URLRequest(url: url)) return webView } @@ -41,7 +68,29 @@ struct WebPageView: View { let url: URL func makeNSView(context: Context) -> WKWebView { - let webView = WKWebView() + let configuration = WKWebViewConfiguration() + let userContentController = WKUserContentController() + + // Inject CSS to support dark mode background + let darkModeCSS = """ + @media (prefers-color-scheme: dark) { + html, body { + background-color: #000000 !important; + color-scheme: dark; + } + } + """ + let cssScript = WKUserScript( + source: + "var style = document.createElement('style'); style.innerHTML = '\(darkModeCSS.replacingOccurrences(of: "\n", with: " "))'; document.head.appendChild(style);", + injectionTime: .atDocumentEnd, + forMainFrameOnly: true + ) + userContentController.addUserScript(cssScript) + configuration.userContentController = userContentController + + let webView = WKWebView(frame: .zero, configuration: configuration) + webView.setValue(false, forKey: "drawsBackground") webView.load(URLRequest(url: url)) return webView } diff --git a/RxNote/RxNoteClips/RxNoteClips.entitlements b/RxNote/RxNoteClips/RxNoteClips.entitlements index 4fda2cb..940fef5 100644 --- a/RxNote/RxNoteClips/RxNoteClips.entitlements +++ b/RxNote/RxNoteClips/RxNoteClips.entitlements @@ -4,8 +4,8 @@ com.apple.developer.associated-domains - applinks:note.rxlab.app - appclips:note.rxlab.app + applinks:rxnote.rxlab.app + appclips:rxnote.rxlab.app com.apple.developer.parent-application-identifiers diff --git a/backend/app/(legal)/layout.tsx b/backend/app/(legal)/layout.tsx index 2fe55f3..0577334 100644 --- a/backend/app/(legal)/layout.tsx +++ b/backend/app/(legal)/layout.tsx @@ -1,3 +1,5 @@ +import { ThemeToggle } from "@/components/theme-toggle"; + export default function LegalLayout({ children, }: { @@ -5,7 +7,8 @@ export default function LegalLayout({ }) { return (
-
{children}
+
+
{children}
); } diff --git a/backend/app/(legal)/loading.tsx b/backend/app/(legal)/loading.tsx new file mode 100644 index 0000000..adbf155 --- /dev/null +++ b/backend/app/(legal)/loading.tsx @@ -0,0 +1,57 @@ +export default function LegalLoading() { + return ( +
+ {/* Title */} +
+ + {/* Subtitle / date */} +
+ + {/* Paragraph block */} +
+
+
+
+
+ + {/* Section heading */} +
+ + {/* Paragraph block */} +
+
+
+
+
+ + {/* Sub-heading */} +
+ + {/* List items */} +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + {/* Section heading */} +
+ + {/* Paragraph block */} +
+
+
+
+
+
+ ); +} diff --git a/backend/app/(legal)/privacy/page.mdx b/backend/app/(legal)/privacy/page.mdx index d22f45c..56c1f9f 100644 --- a/backend/app/(legal)/privacy/page.mdx +++ b/backend/app/(legal)/privacy/page.mdx @@ -7,14 +7,14 @@ export const metadata = { **Last updated: February 1, 2026** -This Privacy Policy describes how RxLab ("we", "us", or "our") collects, uses, and shares information when you use our Storage Management application and related services (collectively, the "Service"). +This Privacy Policy describes how RxLab ("we", "us", or "our") collects, uses, and shares information when you use our RxNote application and related services (collectively, the "Service"). ## Information We Collect ### Information You Provide - **Account Information**: When you create an account, we collect your email address and name through our OAuth authentication provider. -- **Content**: We collect the data you store in the Service, including items, categories, locations, and any associated metadata. +- **Content**: We collect the data you store in the Service, including notes, images, locations, and any associated metadata. - **Communications**: If you contact us for support, we collect your email address and the content of your communications. ### Information Collected Automatically diff --git a/backend/app/(legal)/terms/page.mdx b/backend/app/(legal)/terms/page.mdx index 2c1b1f7..be08bd8 100644 --- a/backend/app/(legal)/terms/page.mdx +++ b/backend/app/(legal)/terms/page.mdx @@ -7,7 +7,7 @@ export const metadata = { **Last updated: February 1, 2026** -Please read these Terms of Service ("Terms") carefully before using the Storage Management application and related services (the "Service") operated by RxLab ("we", "us", or "our"). +Please read these Terms of Service ("Terms") carefully before using the RxNote application and related services (the "Service") operated by RxLab ("we", "us", or "our"). By accessing or using the Service, you agree to be bound by these Terms. If you disagree with any part of these Terms, you may not access the Service. diff --git a/backend/app/globals.css b/backend/app/globals.css index 2658b4b..dc48db9 100644 --- a/backend/app/globals.css +++ b/backend/app/globals.css @@ -4,6 +4,20 @@ @custom-variant dark (&:is(.dark *)); +/* Prevent flash before JS runs (WebViews, slow connections) */ +@media (prefers-color-scheme: dark) { + html { + background-color: oklch(0.145 0 0); + color-scheme: dark; + } +} +@media (prefers-color-scheme: light) { + html { + background-color: oklch(1 0 0); + color-scheme: light; + } +} + @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); diff --git a/backend/app/layout.tsx b/backend/app/layout.tsx index cc0b1a3..8158a3b 100644 --- a/backend/app/layout.tsx +++ b/backend/app/layout.tsx @@ -26,7 +26,15 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + + + +