diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 710a9b3ec..39148f4cf 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -595,6 +595,11 @@ 51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51CE1C0823621EDA005548FC /* RefreshProgressView.xib */; }; 51CE1C0B23622007005548FC /* RefreshProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CE1C0A23622006005548FC /* RefreshProgressView.swift */; }; 51CE1C712367721A005548FC /* testURLsOfCurrentArticle.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 84F9EADB213660A100CF2DE4 /* testURLsOfCurrentArticle.applescript */; }; + 51D0214626ED617100FF2E0F /* core.css in Resources */ = {isa = PBXBuildFile; fileRef = 51D0214526ED617100FF2E0F /* core.css */; }; + 51D0214726ED617100FF2E0F /* core.css in Resources */ = {isa = PBXBuildFile; fileRef = 51D0214526ED617100FF2E0F /* core.css */; }; + 51D0214826ED617100FF2E0F /* core.css in Resources */ = {isa = PBXBuildFile; fileRef = 51D0214526ED617100FF2E0F /* core.css */; }; + 51D0214926ED617100FF2E0F /* core.css in Resources */ = {isa = PBXBuildFile; fileRef = 51D0214526ED617100FF2E0F /* core.css */; }; + 51D0214A26ED617100FF2E0F /* core.css in Resources */ = {isa = PBXBuildFile; fileRef = 51D0214526ED617100FF2E0F /* core.css */; }; 51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkStatusCommand.swift */; }; 51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */; }; 51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D87EE02311D34700E63F03 /* ActivityType.swift */; }; @@ -1853,6 +1858,7 @@ 51CD32C724D2E06C009ABAEF /* Secrets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Secrets; sourceTree = ""; }; 51CE1C0823621EDA005548FC /* RefreshProgressView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RefreshProgressView.xib; sourceTree = ""; }; 51CE1C0A23622006005548FC /* RefreshProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshProgressView.swift; sourceTree = ""; }; + 51D0214526ED617100FF2E0F /* core.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = core.css; sourceTree = ""; }; 51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineDataSource.swift; sourceTree = ""; }; 51D87EE02311D34700E63F03 /* ActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityType.swift; sourceTree = ""; }; 51DC07972552083500A3F79F /* ArticleTextSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleTextSize.swift; sourceTree = ""; }; @@ -3083,6 +3089,7 @@ 51C452A822650DA100C03939 /* Article Rendering */ = { isa = PBXGroup; children = ( + 51D0214526ED617100FF2E0F /* core.css */, B27EEBDF244D15F2000932E6 /* stylesheet.css */, 848362FE2262A30E00DA1D35 /* template.html */, 517630032336215100E15FFF /* main.js */, @@ -4385,6 +4392,7 @@ 51E4995E24A875F300B667CB /* newsfoot.js in Resources */, 517B2EE424B3E8FE001AC46C /* blank.html in Resources */, 5177475C24B39AD500EB0F74 /* Credits.rtf in Resources */, + 51D0214926ED617100FF2E0F /* core.css in Resources */, 51E4995D24A875F300B667CB /* main.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4399,6 +4407,7 @@ 51C0516324A77DF800194D5E /* Assets.xcassets in Resources */, 51E4996524A875F400B667CB /* template.html in Resources */, 517B2EE924B3E8FE001AC46C /* main_multiplatform.js in Resources */, + 51D0214A26ED617100FF2E0F /* core.css in Resources */, 517B2EE524B3E8FE001AC46C /* blank.html in Resources */, 51E4996324A875F400B667CB /* newsfoot.js in Resources */, 51E4996224A875F400B667CB /* main.js in Resources */, @@ -4445,6 +4454,7 @@ 65ED405C235DEF6C0081F399 /* ImportOPMLSheet.xib in Resources */, 65ED405D235DEF6C0081F399 /* SidebarKeyboardShortcuts.plist in Resources */, 514A89A3244FD63F0085E65D /* AddTwitterFeedSheet.xib in Resources */, + 51D0214726ED617100FF2E0F /* core.css in Resources */, 5103A9F5242258C600410853 /* AccountsAddCloudKit.xib in Resources */, 65ED405E235DEF6C0081F399 /* DefaultFeeds.opml in Resources */, 51333D3C2468615D00EB5C91 /* AddRedditFeedSheet.xib in Resources */, @@ -4499,6 +4509,7 @@ 516A09422361248000EAE89B /* Inspector.storyboard in Resources */, 1768140B2564BB8300D98635 /* NetNewsWire_iOSwidgetextension_target.xcconfig in Resources */, 5103A9B424216A4200410853 /* blank.html in Resources */, + 51D0214826ED617100FF2E0F /* core.css in Resources */, 84C9FCA42262A1B800D921D6 /* LaunchScreenPhone.storyboard in Resources */, 51F85BEB22724CB600C787DC /* About.rtf in Resources */, 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */, @@ -4535,6 +4546,7 @@ 517630042336215100E15FFF /* main.js in Resources */, 65ED40A0235DEFF00081F399 /* container-migration.plist in Resources */, 5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */, + 51D0214626ED617100FF2E0F /* core.css in Resources */, 5142194B2353C1CF00E07E2C /* main_mac.js in Resources */, 84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */, B27EEBF9244D15F3000932E6 /* stylesheet.css in Resources */, diff --git a/Shared/Article Rendering/core.css b/Shared/Article Rendering/core.css new file mode 100644 index 000000000..64d5ed46f --- /dev/null +++ b/Shared/Article Rendering/core.css @@ -0,0 +1,137 @@ +/* This is the activity indicator (currently iOS only) that is used while image zooming */ + +.activityIndicatorWrap { + position: relative; +} + +.activityIndicator { + z-index: 1; + width: 64px; + height: 64px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +/* see removeWpSmiley; this rule is kept in case a wp-smiley is encountered without alt text */ + +.wp-smiley { + height: 1em; + max-height: 1em; + } + +/* Hide the external link at the bottom of Daring Fireball posts */ + +.x-netnewswire-hide { + display: none; +} + +/*Block ads and junk*/ + +iframe[src*="feedads"], +iframe[src*="doubleclick"], +iframe[src*="plusone.google"] { + display: none !important; +} + +a[href*=".ads."], +a[href*="feedads"], +a[href*="doubleclick"], +a[href*="//ads."], +a[href*="api.tweetmeme"], +a[href*="delicious.com/post?"], +a[href*="digg.com/submit?"], +a[href*="google.com/bookmarks/mark?"], +a[href*="posterous.com/share?"], +a[href*="tumblr.com/share?"], +a[href*="linkedin.com/shareArticle?"], +a[href*="facebook.com/share.php?"], +a[href*="http://twitter.com/home?"], +a[href*="addtoany.com/share_save"] { + display: none !important; +} + +img[src*=".ads."], +img[src*="//ads."], +img[src*="doubleclick"], +img[src*="feedads"], +img[src*="feedburner"], +img[src*="feedblitz"], +img[src*="share-buttons"] { + display: none !important; +} + +/* Newsfoot specific styles. Structural styles come first, theme styles second */ + +.newsfoot-footnote-container { + position: relative; + display: inline-block; + z-index: 9999; +} + +.newsfoot-footnote-popover { + position: absolute; + display: block; + padding: 0em 1em; + margin: 1em; + top: 0.75em; + max-width: none; + border-radius: 0.3em; + box-sizing: border-box; +} + +.newsfoot-footnote-popover { + left: calc(-1 * (50vw - 1em)); + right: calc(-1 * (50vw - 1em)); +} + +.newsfoot-footnote-popover-arrow { + content: ''; + display: block; + width: 1em; + position: absolute; + top: -0.5em; + left: calc(50% - 0.5em); + height: 1em !important; + transform: rotate(45deg); + z-index:0; +} + +.newsfoot-footnote-popover-inner { + border-radius: calc(0.3em - 1px); + padding: 1em; + position: relative; + z-index: 1; +} + +.newsfoot-footnote-popover-inner :first-child { + margin-top: 0; +} +.newsfoot-footnote-popover-inner :last-child { + margin-bottom: 0; +} + +.newsfoot-footnote-popover .reversefootnote, +.newsfoot-footnote-popover .footnoteBackLink, +.newsfoot-footnote-popover .footnote-return, +.newsfoot-footnote-popover a[href*='#fn'] { + display: none; +} + +sup[id^='fn'] { + vertical-align: baseline; +} + +a.footnote { + display: inline-block; + text-decoration: none; + padding: 0.05em 0.75em; + border-radius: 1em; + min-width: 1em; + text-align: center; + font-size: 0.8em; + line-height: 1em; + position:relative; + top: -0.1em; +} diff --git a/Shared/Article Rendering/stylesheet.css b/Shared/Article Rendering/stylesheet.css index 3b4e306d6..b678c31eb 100644 --- a/Shared/Article Rendering/stylesheet.css +++ b/Shared/Article Rendering/stylesheet.css @@ -1,3 +1,5 @@ +/* Shared iOS and macOS CSS rules. Platform specific rules are at the bottom of this file. */ + body { margin-left: auto; margin-right: auto; @@ -9,12 +11,15 @@ body { a { text-decoration: none; } + a:hover { text-decoration: underline; } + .feedlink { font-weight: bold; } + .headerTable { width: 100%; height: 68px; @@ -56,9 +61,11 @@ body .headerTable { border-bottom: 1px solid var(--header-table-border-color); color: var(--header-color); } + body .header { color: var(--header-color); } + body .header a:link, .header a:visited { color: var(--header-color); } @@ -82,9 +89,11 @@ body > .systemMessage { .feedIcon { border-radius: 4px; } + .rightAlign { text-align: end; } + .leftAlign { text-align: start; } @@ -160,6 +169,7 @@ pre code { .nnw-overflow { overflow-x: auto; } + /* Instead of the last-child bits, border-collapse: collapse could have been used. However, then the inter-cell borders @@ -171,10 +181,12 @@ pre code { border: 1px solid var(--secondary-accent-color); font-size: inherit; } + .nnw-overflow table table { margin-bottom: 0; border: none; } + .nnw-overflow td, .nnw-overflow th { -webkit-hyphens: none; word-break: normal; @@ -191,10 +203,12 @@ pre code { .nnw-overflow :matches(thead, tbody, tfoot):last-child > tr:last-child :matches(td, th) { border-bottom: none; } + .nnw-overflow td pre { border: none; padding: 0; } + .nnw-overflow table[border="0"] { border-width: 0; } @@ -267,19 +281,6 @@ blockquote { border-top: 1px solid var(--header-table-border-color); } -/* Hide the external link at the bottom of Daring Fireball posts */ - -.x-netnewswire-hide { - display: none; -} - -/* see removeWpSmiley; this rule is kept in case a wp-smiley is encountered without alt text */ - -.wp-smiley { - height: 1em; - max-height: 1em; -} - /* Twitter */ .twitterAvatar { @@ -304,126 +305,23 @@ blockquote { font-size: 66%; } -/*Block ads and junk*/ - -iframe[src*="feedads"], -iframe[src*="doubleclick"], -iframe[src*="plusone.google"] { - display: none !important; -} - -a[href*=".ads."], -a[href*="feedads"], -a[href*="doubleclick"], -a[href*="//ads."], -a[href*="api.tweetmeme"], -a[href*="delicious.com/post?"], -a[href*="digg.com/submit?"], -a[href*="google.com/bookmarks/mark?"], -a[href*="posterous.com/share?"], -a[href*="tumblr.com/share?"], -a[href*="linkedin.com/shareArticle?"], -a[href*="facebook.com/share.php?"], -a[href*="http://twitter.com/home?"], -a[href*="addtoany.com/share_save"] { - display: none !important; -} - -img[src*=".ads."], -img[src*="//ads."], -img[src*="doubleclick"], -img[src*="feedads"], -img[src*="feedburner"], -img[src*="feedblitz"], -img[src*="share-buttons"] { - display: none !important; -} - -/* Newsfoot specific styles. Structural styles come first, theme styles second */ -.newsfoot-footnote-container { - position: relative; - display: inline-block; - z-index: 9999; -} - -.newsfoot-footnote-popover { - position: absolute; - display: block; - padding: 0em 1em; - margin: 1em; - top: 0.75em; - max-width: none; - border-radius: 0.3em; - box-sizing: border-box; -} - -.newsfoot-footnote-popover { - left: calc(-1 * (50vw - 1em)); - right: calc(-1 * (50vw - 1em)); -} -.newsfoot-footnote-popover-arrow { - content: ''; - display: block; - width: 1em; - position: absolute; - top: -0.5em; - left: calc(50% - 0.5em); - height: 1em !important; - transform: rotate(45deg); - z-index:0; -} -.newsfoot-footnote-popover-inner { - border-radius: calc(0.3em - 1px); - padding: 1em; - position: relative; - z-index: 1; -} - -.newsfoot-footnote-popover-inner :first-child { - margin-top: 0; -} -.newsfoot-footnote-popover-inner :last-child { - margin-bottom: 0; -} - -.newsfoot-footnote-popover .reversefootnote, -.newsfoot-footnote-popover .footnoteBackLink, -.newsfoot-footnote-popover .footnote-return, -.newsfoot-footnote-popover a[href*='#fn'] { - display: none; -} - -sup[id^='fn'] { - vertical-align: baseline; -} - -a.footnote { - display: inline-block; - text-decoration: none; - padding: 0.05em 0.75em; - border-radius: 1em; - min-width: 1em; - text-align: center; - font-size: 0.8em; - line-height: 1em; - position:relative; - top: -0.1em; -} - -/* light / default */ +/* Newsfoot theme for light mode (default) */ .newsfoot-footnote-popover { background: #ccc; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), 0 3px 6px rgba(0, 0, 0, 0.25); color: black; padding: 1px; } + .newsfoot-footnote-popover-arrow { background: #fafafa; border: 1px solid #ccc; } + .newsfoot-footnote-popover-inner { background: #fafafa; } + body a.footnote, body a.footnote:visited, .newsfoot-footnote-popover + a.footnote:hover { @@ -431,25 +329,29 @@ body a.footnote:visited, color: white; transition: background-color 200ms ease-out; } + a.footnote:hover, .newsfoot-footnote-popover + a.footnote { background: #666; transition: background-color 200ms ease-out; } -/* dark */ +/* Newsfoot theme for dark mode */ @media screen and (prefers-color-scheme: dark) { .newsfoot-footnote-popover { background: #444; color: rgb(224, 224, 224); } + .newsfoot-footnote-popover-arrow { background: #242424; border: 1px solid #444; } + .newsfoot-footnote-popover-inner { background: #242424; } + body a.footnote, body a.footnote:visited, .newsfoot-footnote-popover + a.footnote:hover { @@ -457,11 +359,13 @@ a.footnote:hover, color: white; transition: background-color 200ms ease-out; } + a.footnote:hover, .newsfoot-footnote-popover + a.footnote { background: #666; transition: background-color 200ms ease-out; } + } /* iOS Specific */ @@ -481,6 +385,7 @@ a.footnote:hover, :root { color-scheme: light dark; font: -apple-system-body; + /* The font-size is replaced at runtime by the dynamic type size */ font-size: [[font-size]]px; --primary-accent-color: #086AEE; --secondary-accent-color: #086AEE; @@ -499,18 +404,16 @@ a.footnote:hover, body a, body a:visited { color: var(--secondary-accent-color); } + body .header { font: -apple-system-body; font-size: [[font-size]]px; } + body .header a:link, body .header a:visited { color: var(--primary-accent-color); } - .avatar img { - border-radius: 4px; - } - pre { border: 1px solid var(--secondary-accent-color); padding: 5px; @@ -520,20 +423,6 @@ a.footnote:hover, border: 1px solid var(--secondary-accent-color); } - .activityIndicatorWrap { - position: relative; - } - - .activityIndicator { - z-index: 1; - width: 64px; - height: 64px; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - } /* macOS Specific */ diff --git a/Shared/ArticleStyles/ArticleTheme.swift b/Shared/ArticleStyles/ArticleTheme.swift index 4a5f086d7..a32e37af2 100644 --- a/Shared/ArticleStyles/ArticleTheme.swift +++ b/Shared/ArticleStyles/ArticleTheme.swift @@ -43,30 +43,30 @@ struct ArticleTheme: Equatable { self.path = nil; self.info = ["CreatorHomePage": "https://netnewswire.com/", "CreatorName": "Ranchero Software", "Version": "1.0"] - let cssPath = Bundle.main.path(forResource: "stylesheet", ofType: "css")! - css = Self.stringAtPath(cssPath) + let corePath = Bundle.main.path(forResource: "core", ofType: "css")! + let stylesheetPath = Bundle.main.path(forResource: "stylesheet", ofType: "css")! + css = Self.stringAtPath(corePath)! + "\n" + Self.stringAtPath(stylesheetPath)! let templatePath = Bundle.main.path(forResource: "template", ofType: "html")! - template = Self.stringAtPath(templatePath) + template = Self.stringAtPath(templatePath)! } init(path: String) { self.path = path - if FileManager.default.isFolder(atPath: path) { - let infoPath = (path as NSString).appendingPathComponent("Info.plist") - self.info = NSDictionary(contentsOfFile: infoPath) + let infoPath = (path as NSString).appendingPathComponent("Info.plist") + self.info = NSDictionary(contentsOfFile: infoPath) - let cssPath = (path as NSString).appendingPathComponent("stylesheet.css") - self.css = Self.stringAtPath(cssPath) - - let templatePath = (path as NSString).appendingPathComponent("template.html") - self.template = Self.stringAtPath(templatePath) + let corePath = Bundle.main.path(forResource: "core", ofType: "css")! + let stylesheetPath = (path as NSString).appendingPathComponent("stylesheet.css") + if let stylesheetCSS = Self.stringAtPath(stylesheetPath) { + self.css = Self.stringAtPath(corePath)! + "\n" + stylesheetCSS } else { - self.css = Self.stringAtPath(path) - self.template = nil - self.info = nil + self.css = nil } + + let templatePath = (path as NSString).appendingPathComponent("template.html") + self.template = Self.stringAtPath(templatePath) } static func stringAtPath(_ f: String) -> String? {