WIP: New themes and reader preferences for iOS
This commit is contained in:
@ -83,8 +83,11 @@ final class AppStoreScreenshots: XCTestCase {
|
||||
func testScreenshotSubscriptions() throws {
|
||||
let app = XCUIApplication()
|
||||
setupSnapshot(app)
|
||||
app.navigationBars["Home"]/*@START_MENU_TOKEN@*/ .buttons["_profile"]/*[[".otherElements[\"_profile\"].buttons[\"_profile\"]",".buttons[\"_profile\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/ .tap()
|
||||
app.collectionViews.buttons["Subscriptions"].tap()
|
||||
// app.navigationBars.firstMatch.buttons["person.circle"].tap()
|
||||
// app.collectionViews.buttons["Subscriptions"].tap()
|
||||
//
|
||||
// XCUIApplication().navigationBars["_TtGC7SwiftUI19UIHosting"]/*@START_MENU_TOKEN@*/.buttons["ToggleSidebar"]/*[[".buttons[\"Show Sidebar\"]",".buttons[\"ToggleSidebar\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
|
||||
//
|
||||
|
||||
snapshot("Newsletters")
|
||||
|
||||
|
||||
@ -89,6 +89,7 @@ struct WebReader: PlatformViewRepresentable {
|
||||
|
||||
if readerSettingsChangedTransactionID != context.coordinator.previousReaderSettingsChangedUUID {
|
||||
context.coordinator.previousReaderSettingsChangedUUID = readerSettingsChangedTransactionID
|
||||
(webView as? OmnivoreWebView)?.updateTheme()
|
||||
(webView as? OmnivoreWebView)?.updateFontFamily()
|
||||
(webView as? OmnivoreWebView)?.updateFontSize()
|
||||
(webView as? OmnivoreWebView)?.updateTextContrast()
|
||||
|
||||
@ -240,7 +240,8 @@ struct WebReaderContainerView: View {
|
||||
}
|
||||
.frame(height: readerViewNavBarHeight * navBarVisibilityRatio)
|
||||
.opacity(navBarVisibilityRatio)
|
||||
.background(Color.systemBackground)
|
||||
.background(Color.black)
|
||||
.background(Theme.fromName(themeName: ThemeManager.currentThemeName)?.bgColor ?? .clear)
|
||||
.alert("Are you sure?", isPresented: $showDeleteConfirmation) {
|
||||
Button("Remove Link", role: .destructive) {
|
||||
Snackbar.show(message: "Link removed")
|
||||
@ -301,6 +302,7 @@ struct WebReaderContainerView: View {
|
||||
annotation: $annotation,
|
||||
showBottomBar: $showBottomBar
|
||||
)
|
||||
.background(Theme.fromName(themeName: ThemeManager.currentThemeName)?.bgColor ?? .clear)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
navBarVisibilityRatio = 1
|
||||
|
||||
@ -16,7 +16,7 @@ struct WebReaderContent {
|
||||
init(
|
||||
item: LinkedItem,
|
||||
articleContent: ArticleContent,
|
||||
isDark: Bool,
|
||||
isDark _: Bool,
|
||||
fontSize: Int,
|
||||
lineHeight: Int,
|
||||
maxWidthPercentage: Int,
|
||||
@ -27,7 +27,7 @@ struct WebReaderContent {
|
||||
self.lineHeight = lineHeight
|
||||
self.maxWidthPercentage = maxWidthPercentage
|
||||
self.item = item
|
||||
self.themeKey = isDark ? "Gray" : "LightGray"
|
||||
self.themeKey = ThemeManager.currentThemeName // isDark ? "Gray" : "Charcoal"
|
||||
self.fontFamily = fontFamily
|
||||
self.articleContent = articleContent
|
||||
self.prefersHighContrastText = prefersHighContrastText
|
||||
|
||||
@ -74,7 +74,7 @@ extension WebReaderCoordinator: WKNavigationDelegate {
|
||||
func webView(_ webView: WKWebView, didFinish _: WKNavigation!) {
|
||||
#if os(iOS)
|
||||
webView.isOpaque = true
|
||||
webView.backgroundColor = .systemBackground
|
||||
webView.backgroundColor = .clear
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ struct SpeechSynthesizer {
|
||||
func createPlayerItems(from: Int) -> [SpeechItem] {
|
||||
var result: [SpeechItem] = []
|
||||
|
||||
for idx in from ..< document.utterances.count {
|
||||
for idx in from ..< min(7, document.utterances.count) {
|
||||
let utterance = document.utterances[idx]
|
||||
let voiceStr = utterance.voice ?? document.defaultVoice
|
||||
let segmentStr = String(format: "%04d", arguments: [idx])
|
||||
|
||||
@ -19,4 +19,5 @@ public enum UserDefaultKey: String {
|
||||
case textToSpeechPreloadEnabled
|
||||
case recentSearchTerms
|
||||
case audioPlayerExpanded
|
||||
case themeName
|
||||
}
|
||||
|
||||
@ -44,6 +44,12 @@ public final class OmnivoreWebView: WKWebView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func updateTheme() {
|
||||
if let themeName = UserDefaults.standard.value(forKey: UserDefaultKey.themeName.rawValue) as? String {
|
||||
dispatchEvent(.updateTheme(themeName: "Gray" /* themeName */ ))
|
||||
}
|
||||
}
|
||||
|
||||
public func updateFontFamily() {
|
||||
if let fontFamily = UserDefaults.standard.value(forKey: UserDefaultKey.preferredWebFont.rawValue) as? String {
|
||||
dispatchEvent(.updateFontFamily(family: fontFamily))
|
||||
@ -293,6 +299,7 @@ public enum WebViewDispatchEvent {
|
||||
case updateFontSize(size: Int)
|
||||
case updateColorMode(isDark: Bool)
|
||||
case updateFontFamily(family: String)
|
||||
case updateTheme(themeName: String)
|
||||
case saveAnnotation(annotation: String)
|
||||
case annotate
|
||||
case highlight
|
||||
@ -320,6 +327,8 @@ public enum WebViewDispatchEvent {
|
||||
return "updateColorMode"
|
||||
case .updateFontFamily:
|
||||
return "updateFontFamily"
|
||||
case .updateTheme:
|
||||
return "updateTheme"
|
||||
case .saveAnnotation:
|
||||
return "saveAnnotation"
|
||||
case .annotate:
|
||||
@ -347,6 +356,8 @@ public enum WebViewDispatchEvent {
|
||||
return "event.lineHeight = '\(height)';"
|
||||
case let .updateMaxWidthPercentage(maxWidthPercentage: maxWidthPercentage):
|
||||
return "event.maxWidthPercentage = '\(maxWidthPercentage)';"
|
||||
case let .updateTheme(themeName: themeName):
|
||||
return "event.themeName = '\(themeName)';"
|
||||
case let .updateFontSize(size: size):
|
||||
return "event.fontSize = '\(size)';"
|
||||
case let .updateColorMode(isDark: isDark):
|
||||
|
||||
@ -69,81 +69,112 @@ public enum WebFont: String, CaseIterable {
|
||||
.navigationTitle("Reader Font")
|
||||
}
|
||||
|
||||
var themePicker: some View {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(spacing: 16) {
|
||||
ForEach(Theme.allCases, id: \.self) { theme in
|
||||
VStack {
|
||||
ZStack {
|
||||
Circle()
|
||||
.foregroundColor(theme.bgColor)
|
||||
.frame(minWidth: 32, minHeight: 32)
|
||||
.padding(8)
|
||||
}
|
||||
|
||||
Text(theme.rawValue).font(.appCaption)
|
||||
}
|
||||
.padding(8)
|
||||
.background(Color(red: 248 / 255.0, green: 248 / 255.0, blue: 248 / 255.0))
|
||||
.onTapGesture {
|
||||
ThemeManager.currentThemeName = theme.rawValue
|
||||
updateReaderPreferences()
|
||||
}
|
||||
.cornerRadius(8)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.stroke(ThemeManager.currentThemeName == theme.rawValue ? Color.appCtaYellow : .clear, lineWidth: 2)
|
||||
)
|
||||
.padding(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
NavigationView {
|
||||
ScrollView(showsIndicators: false) {
|
||||
VStack(alignment: .center) {
|
||||
VStack {
|
||||
LabelledStepper(
|
||||
labelText: "Font Size:",
|
||||
onIncrement: {
|
||||
storedFontSize = min(storedFontSize + 2, 28)
|
||||
updateReaderPreferences()
|
||||
},
|
||||
onDecrement: {
|
||||
storedFontSize = max(storedFontSize - 2, 10)
|
||||
updateReaderPreferences()
|
||||
}
|
||||
)
|
||||
VStack(alignment: .center) {
|
||||
themePicker
|
||||
.padding(.bottom, 16)
|
||||
|
||||
LabelledStepper(
|
||||
labelText: "Margin:",
|
||||
onIncrement: {
|
||||
storedMaxWidthPercentage = max(storedMaxWidthPercentage - 10, 40)
|
||||
updateReaderPreferences()
|
||||
},
|
||||
onDecrement: {
|
||||
storedMaxWidthPercentage = min(storedMaxWidthPercentage + 10, 100)
|
||||
updateReaderPreferences()
|
||||
}
|
||||
)
|
||||
|
||||
LabelledStepper(
|
||||
labelText: "Line Spacing:",
|
||||
onIncrement: {
|
||||
storedLineSpacing = min(storedLineSpacing + 25, 300)
|
||||
updateReaderPreferences()
|
||||
},
|
||||
onDecrement: {
|
||||
storedLineSpacing = max(storedLineSpacing - 25, 100)
|
||||
updateReaderPreferences()
|
||||
}
|
||||
)
|
||||
|
||||
Toggle("High Contrast Text:", isOn: $prefersHighContrastText)
|
||||
.frame(height: 40)
|
||||
.padding(.trailing, 6)
|
||||
.onChange(of: prefersHighContrastText) { _ in
|
||||
updateReaderPreferences()
|
||||
}
|
||||
|
||||
HStack {
|
||||
NavigationLink(destination: fontList) {
|
||||
Text("Change Reader Font")
|
||||
}
|
||||
Image(systemName: "chevron.right")
|
||||
Spacer()
|
||||
}
|
||||
.frame(height: 40)
|
||||
|
||||
Spacer()
|
||||
LabelledStepper(
|
||||
labelText: "Font Size",
|
||||
onIncrement: {
|
||||
storedFontSize = min(storedFontSize + 2, 28)
|
||||
updateReaderPreferences()
|
||||
},
|
||||
onDecrement: {
|
||||
storedFontSize = max(storedFontSize - 2, 10)
|
||||
updateReaderPreferences()
|
||||
}
|
||||
)
|
||||
|
||||
LabelledStepper(
|
||||
labelText: "Margin",
|
||||
onIncrement: {
|
||||
storedMaxWidthPercentage = max(storedMaxWidthPercentage - 10, 40)
|
||||
updateReaderPreferences()
|
||||
},
|
||||
onDecrement: {
|
||||
storedMaxWidthPercentage = min(storedMaxWidthPercentage + 10, 100)
|
||||
updateReaderPreferences()
|
||||
}
|
||||
)
|
||||
|
||||
LabelledStepper(
|
||||
labelText: "Line Spacing",
|
||||
onIncrement: {
|
||||
storedLineSpacing = min(storedLineSpacing + 25, 300)
|
||||
updateReaderPreferences()
|
||||
},
|
||||
onDecrement: {
|
||||
storedLineSpacing = max(storedLineSpacing - 25, 100)
|
||||
updateReaderPreferences()
|
||||
}
|
||||
)
|
||||
|
||||
HStack {
|
||||
NavigationLink(destination: fontList) {
|
||||
Text("Font")
|
||||
}
|
||||
Spacer()
|
||||
Button(action: {}, label: { Text("Crimson Text").frame(width: 91) })
|
||||
.buttonStyle(RoundedRectButtonStyle())
|
||||
}
|
||||
.frame(height: 40)
|
||||
|
||||
Toggle("High Contrast Text:", isOn: $prefersHighContrastText)
|
||||
.frame(height: 40)
|
||||
.padding(.trailing, 6)
|
||||
.onChange(of: prefersHighContrastText) { _ in
|
||||
updateReaderPreferences()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.navigationTitle("Reader Preferences")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .barTrailing) {
|
||||
Button(
|
||||
action: dismissAction,
|
||||
label: { Text("Done").foregroundColor(.appGrayTextContrast).padding() }
|
||||
)
|
||||
}
|
||||
}
|
||||
// .toolbar {
|
||||
// ToolbarItem(placement: .barTrailing) {
|
||||
// Button(
|
||||
// action: dismissAction,
|
||||
// label: { Text("Done").foregroundColor(.appGrayTextContrast).padding() }
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
.accentColor(.appGrayTextContrast)
|
||||
// .navigationViewStyle(.stack)
|
||||
// .accentColor(.appGrayTextContrast)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
54
apple/OmnivoreKit/Sources/Views/Theme.swift
Normal file
54
apple/OmnivoreKit/Sources/Views/Theme.swift
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Jackson Harper on 10/27/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Utils
|
||||
|
||||
public enum Theme: String, CaseIterable {
|
||||
case system = "System"
|
||||
case sepia = "Sepia"
|
||||
case charcoal = "Charcoal"
|
||||
case mint = "Mint"
|
||||
|
||||
case solarized = "Solarized"
|
||||
|
||||
case light = "Light"
|
||||
case dark = "Dark"
|
||||
|
||||
public var bgColor: Color {
|
||||
switch self {
|
||||
case .system:
|
||||
return Color.systemBackground
|
||||
case .charcoal:
|
||||
return Color(red: 48 / 255.0, green: 48 / 255.0, blue: 48 / 255.0)
|
||||
case .sepia:
|
||||
return Color(red: 249 / 255.0, green: 241 / 255.0, blue: 220 / 255.0)
|
||||
case .mint:
|
||||
return Color(red: 202 / 255.0, green: 230 / 255.0, blue: 208 / 255.0)
|
||||
case .solarized:
|
||||
return Color(red: 13 / 255.0, green: 39 / 255.0, blue: 50 / 255.0)
|
||||
case .light:
|
||||
return Color.white
|
||||
case .dark:
|
||||
return Color.black
|
||||
}
|
||||
}
|
||||
|
||||
public static func fromName(themeName: String) -> Theme? {
|
||||
for theme in Theme.allCases {
|
||||
if theme.rawValue == themeName {
|
||||
return theme
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public enum ThemeManager {
|
||||
@AppStorage(UserDefaultKey.themeName.rawValue) public static var currentThemeName = "System"
|
||||
}
|
||||
@ -19,7 +19,7 @@ import WebKit
|
||||
webView.isOpaque = false
|
||||
webView.backgroundColor = UIColor.clear
|
||||
if let url = request.url {
|
||||
let themeID = Color.isDarkMode ? "Gray" : "LightGray"
|
||||
let themeID = Color.isDarkMode ? "Gray" /* "Sepia" */ : "Charcoal"
|
||||
webView.injectCookie(cookieString: "theme=\(themeID); Max-Age=31536000;", url: url)
|
||||
}
|
||||
return webView
|
||||
@ -51,7 +51,7 @@ import WebKit
|
||||
if let url = request.url {
|
||||
// Dark mode is still rendering a white background on mac for some reason.
|
||||
// Forcing light mode for now until we figure out a fix
|
||||
let themeID = "LightGray" // NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua ? "Gray" : "LightGray"
|
||||
let themeID = "Charcoal" // NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua ? "Gray" : "LightGray"
|
||||
webView.injectCookie(cookieString: "theme=\(themeID); Max-Age=31536000;", url: url)
|
||||
}
|
||||
return webView
|
||||
|
||||
@ -11,7 +11,7 @@ import { ReportIssuesModal } from './ReportIssuesModal'
|
||||
import { reportIssueMutation } from '../../../lib/networking/mutations/reportIssueMutation'
|
||||
import { ArticleHeaderToolbar } from './ArticleHeaderToolbar'
|
||||
import { userPersonalizationMutation } from '../../../lib/networking/mutations/userPersonalizationMutation'
|
||||
import { updateThemeLocally } from '../../../lib/themeUpdater'
|
||||
import { updateTheme, updateThemeLocally } from '../../../lib/themeUpdater'
|
||||
import { ArticleMutations } from '../../../lib/articleActions'
|
||||
import { LabelChip } from '../../elements/LabelChip'
|
||||
import { Label } from '../../../lib/networking/fragments/labelFragment'
|
||||
@ -121,6 +121,17 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateThemeEvent extends Event {
|
||||
themeName?: string
|
||||
}
|
||||
|
||||
const handleThemeChange = async (event: UpdateThemeEvent) => {
|
||||
const newTheme = event.themeName
|
||||
if (newTheme) {
|
||||
updateTheme(newTheme)
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateColorModeEvent extends Event {
|
||||
isDark?: string
|
||||
}
|
||||
@ -145,6 +156,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
'updateMaxWidthPercentage',
|
||||
updateMaxWidthPercentage
|
||||
)
|
||||
document.addEventListener('updateTheme', handleThemeChange)
|
||||
document.addEventListener('updateFontSize', handleFontSizeChange)
|
||||
document.addEventListener('updateColorMode', updateColorMode)
|
||||
document.addEventListener(
|
||||
@ -160,6 +172,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
'updateMaxWidthPercentage',
|
||||
updateMaxWidthPercentage
|
||||
)
|
||||
document.removeEventListener('updateTheme', handleThemeChange)
|
||||
document.removeEventListener('updateFontSize', handleFontSizeChange)
|
||||
document.removeEventListener('updateColorMode', updateColorMode)
|
||||
document.removeEventListener(
|
||||
@ -179,7 +192,6 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
readerFontColor: highContrastFont
|
||||
? theme.colors.readerFontHighContrast.toString()
|
||||
: theme.colors.readerFont.toString(),
|
||||
readerFontColorTransparent: theme.colors.readerFontTransparent.toString(),
|
||||
readerTableHeaderColor: theme.colors.readerTableHeader.toString(),
|
||||
readerHeadersColor: theme.colors.readerHeader.toString(),
|
||||
}
|
||||
@ -192,8 +204,8 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
padding: '16px',
|
||||
maxWidth: `${styles.maxWidthPercentage ?? 100}%`,
|
||||
background: props.isAppleAppEmbed
|
||||
? 'unset'
|
||||
: theme.colors.grayBg.toString(),
|
||||
? theme.colors.readerBg.toString()
|
||||
: theme.colors.readerBg.toString(),
|
||||
'--text-font-family': styles.fontFamily,
|
||||
'--text-font-size': `${styles.fontSize}px`,
|
||||
'--line-height': `${styles.lineHeight}%`,
|
||||
@ -202,7 +214,6 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
'--figure-margin': '1.6rem auto',
|
||||
'--hr-margin': '1em',
|
||||
'--font-color': styles.readerFontColor,
|
||||
'--font-color-transparent': styles.readerFontColorTransparent,
|
||||
'--table-header-color': styles.readerTableHeaderColor,
|
||||
'--headers-color': styles.readerHeadersColor,
|
||||
'@sm': {
|
||||
@ -227,6 +238,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
fontFamily: styles.fontFamily,
|
||||
width: '100%',
|
||||
wordWrap: 'break-word',
|
||||
color: '$readerFont',
|
||||
}}
|
||||
>
|
||||
{props.article.title}
|
||||
|
||||
@ -126,7 +126,7 @@ export function ReaderSettingsControl(props: ReaderSettingsProps): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
color={theme.colors.readerFontTransparent.toString()}
|
||||
color={theme.colors.readerFont.toString()}
|
||||
css={{ pl: '12px', m: '0px', pt: '14px' }}
|
||||
>
|
||||
Margin:
|
||||
@ -193,7 +193,7 @@ export function ReaderSettingsControl(props: ReaderSettingsProps): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
color={theme.colors.readerFontTransparent.toString()}
|
||||
color={theme.colors.readerFont.toString()}
|
||||
css={{ pl: '12px', m: '0px', pt: '14px' }}
|
||||
>
|
||||
Line Spacing:
|
||||
|
||||
@ -17,7 +17,6 @@ export function SkeletonArticleContainer(props: SkeletonArticleContainerProps):
|
||||
lineHeight: props.lineHeight ?? 150,
|
||||
fontFamily: props.fontFamily ?? 'inter',
|
||||
readerFontColor: theme.colors.readerFont.toString(),
|
||||
readerFontColorTransparent: theme.colors.readerFontTransparent.toString(),
|
||||
readerTableHeaderColor: theme.colors.readerTableHeader.toString(),
|
||||
readerHeadersColor: theme.colors.readerHeader.toString(),
|
||||
}
|
||||
@ -40,7 +39,6 @@ export function SkeletonArticleContainer(props: SkeletonArticleContainerProps):
|
||||
'--figure-margin': '1.6rem auto',
|
||||
'--hr-margin': '1em',
|
||||
'--font-color': styles.readerFontColor,
|
||||
'--font-color-transparent': styles.readerFontColorTransparent,
|
||||
'--table-header-color': styles.readerTableHeaderColor,
|
||||
'--headers-color': styles.readerHeadersColor,
|
||||
'@sm': {
|
||||
|
||||
@ -6,6 +6,8 @@ export enum ThemeId {
|
||||
Light = 'LightGray',
|
||||
Dark = 'Gray',
|
||||
Darker = 'Dark',
|
||||
Sepia = 'Sepia',
|
||||
Charcoal = 'Charcoal'
|
||||
}
|
||||
|
||||
export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
|
||||
@ -144,11 +146,10 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
|
||||
omnivoreCtaYellow: 'rgb(255, 210, 52)',
|
||||
|
||||
// Reader Colors
|
||||
readerBg: '#E5E5E5',
|
||||
readerFont: '#3D3D3D',
|
||||
readerFontHighContrast: 'black',
|
||||
readerFontTransparent: 'rgba(61,61,61,0.65)',
|
||||
readerHeader: '3D3D3D',
|
||||
readerBg: '#F9F1DC', // #E5E5E5',
|
||||
readerFont: '#554A34',
|
||||
readerFontHighContrast: '#342100', // black',
|
||||
readerHeader: '554A34',
|
||||
readerTableHeader: '#FFFFFF',
|
||||
|
||||
// Avatar Fallback color
|
||||
@ -211,7 +212,6 @@ const darkThemeSpec = {
|
||||
readerBg: '#303030',
|
||||
readerFont: '#b9b9b9',
|
||||
readerFontHighContrast: 'white',
|
||||
readerFontTransparent: 'rgba(185,185,185,0.65)',
|
||||
readerHeader: '#b9b9b9',
|
||||
readerTableHeader: '#FFFFFF',
|
||||
tooltipIcons: '#5F5E58',
|
||||
@ -236,12 +236,35 @@ const darkThemeSpec = {
|
||||
},
|
||||
}
|
||||
|
||||
// Avatar Fallback color
|
||||
const sepiaThemeSpec = {
|
||||
colors: {
|
||||
// Reader Colors
|
||||
readerBg: '#F9F1DC',
|
||||
readerFont: '#554A34',
|
||||
readerFontHighContrast: 'black',
|
||||
readerHeader: '554A34',
|
||||
readerTableHeader: '#FFFFFF',
|
||||
}
|
||||
}
|
||||
|
||||
const charcoalThemeSpec = {
|
||||
colors: {
|
||||
// Reader Colors
|
||||
readerBg: '#303030',
|
||||
readerFont: '#b9b9b9',
|
||||
readerFontHighContrast: 'white',
|
||||
readerHeader: '#b9b9b9',
|
||||
readerTableHeader: '#FFFFFF',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Dark and Darker theme now match each other.
|
||||
// Use the darkThemeSpec object to make updates.
|
||||
export const darkTheme = createTheme(ThemeId.Dark, darkThemeSpec)
|
||||
export const darkerTheme = createTheme(ThemeId.Darker, darkThemeSpec)
|
||||
export const sepiaTheme = createTheme(ThemeId.Sepia, {...darkThemeSpec, ...sepiaThemeSpec})
|
||||
export const charcoalTheme = createTheme(ThemeId.Charcoal, {...darkThemeSpec, ...charcoalThemeSpec})
|
||||
|
||||
// Lighter theme now matches the default theme.
|
||||
// This only exists for users that might still have a lighter theme set
|
||||
|
||||
@ -3,6 +3,8 @@ import {
|
||||
lighterTheme,
|
||||
darkTheme,
|
||||
darkerTheme,
|
||||
sepiaTheme,
|
||||
charcoalTheme,
|
||||
} from '../components/tokens/stitches.config'
|
||||
import { userPersonalizationMutation } from './networking/mutations/userPersonalizationMutation'
|
||||
|
||||
@ -26,7 +28,9 @@ export function updateThemeLocally(themeId: string): void {
|
||||
lighterTheme,
|
||||
ThemeId.Light,
|
||||
darkTheme,
|
||||
darkerTheme
|
||||
darkerTheme,
|
||||
sepiaTheme,
|
||||
charcoalTheme
|
||||
)
|
||||
document.body.classList.add(themeId)
|
||||
}
|
||||
@ -41,6 +45,10 @@ export function currentThemeName(): string {
|
||||
return 'Darker'
|
||||
case ThemeId.Lighter:
|
||||
return 'Lighter'
|
||||
case ThemeId.Sepia:
|
||||
return 'Sepia'
|
||||
case ThemeId.Charcoal:
|
||||
return 'Charcoal'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable functional/no-class */
|
||||
import { useEffect } from 'react'
|
||||
import NextDocument, { Html, Head, Main, NextScript } from 'next/document'
|
||||
import { getCssText, globalStyles } from '../components/tokens/stitches.config'
|
||||
|
||||
@ -35,7 +34,7 @@ export default class Document extends NextDocument {
|
||||
var themeId = window.localStorage.getItem('theme')
|
||||
|
||||
if (themeId) {
|
||||
document.body.classList.remove('theme-default', 'White', 'Gray', 'LightGray', 'Dark')
|
||||
document.body.classList.remove('theme-default', 'White', 'Gray', 'LightGray', 'Dark', 'Sepia', 'Charcoal')
|
||||
document.body.classList.add(themeId)
|
||||
}
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user