Merge pull request #462 from vincode-io/issue-455
Changed the article detail pane to always use the webview. Issue #455
This commit is contained in:
commit
7b4e096911
|
@ -624,59 +624,9 @@
|
||||||
</customView>
|
</customView>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="containerView" destination="cJ9-6s-66u" id="gXc-Pz-9sQ"/>
|
<outlet property="containerView" destination="cJ9-6s-66u" id="gXc-Pz-9sQ"/>
|
||||||
<outlet property="noSelectionView" destination="aEc-1k-VmJ" id="KLS-ln-T1K"/>
|
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="vzM-Vn-mEn" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="vzM-Vn-mEn" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
<customView id="aEc-1k-VmJ" customClass="NoSelectionView" customModule="NetNewsWire" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="613" height="96"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<box boxType="custom" borderType="none" borderWidth="0.0" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="Zb8-hH-gIZ">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="613" height="96"/>
|
|
||||||
<view key="contentView" id="Gmh-qL-lA5">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="613" height="96"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ECt-Wi-zkb">
|
|
||||||
<rect key="frame" x="266" y="40" width="109" height="22"/>
|
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="No selection" usesSingleLineMode="YES" id="oNn-so-m7W">
|
|
||||||
<font key="font" metaFont="systemSemibold" size="18"/>
|
|
||||||
<color key="textColor" name="tertiaryLabelColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1AW-Ay-XS8">
|
|
||||||
<rect key="frame" x="408" y="39" width="154" height="22"/>
|
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Multiple selection" usesSingleLineMode="YES" id="vhD-gM-NUy">
|
|
||||||
<font key="font" metaFont="systemSemibold" size="18"/>
|
|
||||||
<color key="textColor" name="tertiaryLabelColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="1AW-Ay-XS8" firstAttribute="centerY" secondItem="Gmh-qL-lA5" secondAttribute="centerY" constant="-64" id="9uN-K3-d35"/>
|
|
||||||
<constraint firstItem="ECt-Wi-zkb" firstAttribute="centerX" secondItem="Gmh-qL-lA5" secondAttribute="centerX" id="QDc-Y3-Nn4"/>
|
|
||||||
<constraint firstItem="1AW-Ay-XS8" firstAttribute="centerX" secondItem="Gmh-qL-lA5" secondAttribute="centerX" id="QV5-qP-Ys6"/>
|
|
||||||
<constraint firstItem="ECt-Wi-zkb" firstAttribute="centerY" secondItem="Gmh-qL-lA5" secondAttribute="centerY" constant="-64" id="yQr-wJ-pBL"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<color key="borderColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
|
||||||
<color key="fillColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</box>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="Zb8-hH-gIZ" firstAttribute="leading" secondItem="aEc-1k-VmJ" secondAttribute="leading" id="5Ay-6o-LZ1"/>
|
|
||||||
<constraint firstItem="Zb8-hH-gIZ" firstAttribute="top" secondItem="aEc-1k-VmJ" secondAttribute="top" id="Wb7-Zp-hj0"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="Zb8-hH-gIZ" secondAttribute="trailing" id="cYM-up-kUN"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="Zb8-hH-gIZ" secondAttribute="bottom" id="gCy-5R-aK2"/>
|
|
||||||
</constraints>
|
|
||||||
<connections>
|
|
||||||
<outlet property="multipleSelectionLabel" destination="1AW-Ay-XS8" id="gK2-Ya-Dz7"/>
|
|
||||||
<outlet property="noSelectionLabel" destination="ECt-Wi-zkb" id="Dvq-DU-MxC"/>
|
|
||||||
</connections>
|
|
||||||
</customView>
|
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="68" y="946"/>
|
<point key="canvasLocation" x="68" y="946"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
|
|
@ -18,7 +18,7 @@ var cachedTemplate = ""
|
||||||
|
|
||||||
class ArticleRenderer {
|
class ArticleRenderer {
|
||||||
|
|
||||||
let article: Article
|
let article: Article?
|
||||||
let articleStyle: ArticleStyle
|
let articleStyle: ArticleStyle
|
||||||
let appearance: NSAppearance?
|
let appearance: NSAppearance?
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class ArticleRenderer {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var title: String = {
|
lazy var title: String = {
|
||||||
if let articleTitle = self.article.title {
|
if let articleTitle = self.article?.title {
|
||||||
return articleTitle
|
return articleTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +56,12 @@ class ArticleRenderer {
|
||||||
|
|
||||||
lazy var baseURL: URL? = {
|
lazy var baseURL: URL? = {
|
||||||
|
|
||||||
var s = self.article.url
|
var s = self.article?.url
|
||||||
if s == nil {
|
if s == nil {
|
||||||
s = self.article.feed?.homePageURL
|
s = self.article?.feed?.homePageURL
|
||||||
}
|
}
|
||||||
if s == nil {
|
if s == nil {
|
||||||
s = self.article.feed?.url
|
s = self.article?.feed?.url
|
||||||
}
|
}
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -84,17 +84,25 @@ class ArticleRenderer {
|
||||||
return nil
|
return nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var html: String {
|
var articleHTML: String {
|
||||||
|
let body = RSMacroProcessor.renderedText(withTemplate: template(), substitutions: substitutions(), macroStart: "[[", macroEnd: "]]")
|
||||||
return renderedHTML()
|
return renderHTML(withBody: body)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(article: Article, style: ArticleStyle, appearance: NSAppearance? = nil) {
|
var multipleSelectionHTML: String {
|
||||||
|
let body = "<h3 class='systemMessage'>Multiple selection</h3>"
|
||||||
|
return renderHTML(withBody: body)
|
||||||
|
}
|
||||||
|
|
||||||
|
var noSelectionHTML: String {
|
||||||
|
let body = "<h3 class='systemMessage'>No selection</h3>"
|
||||||
|
return renderHTML(withBody: body)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(article: Article?, style: ArticleStyle, appearance: NSAppearance? = nil) {
|
||||||
self.article = article
|
self.article = article
|
||||||
self.articleStyle = style
|
self.articleStyle = style
|
||||||
self.appearance = appearance
|
self.appearance = appearance
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
@ -157,7 +165,7 @@ class ArticleRenderer {
|
||||||
|
|
||||||
private func titleOrTitleLink() -> String {
|
private func titleOrTitleLink() -> String {
|
||||||
|
|
||||||
if let link = article.preferredLink {
|
if let link = article?.preferredLink {
|
||||||
return linkWithText(title, link)
|
return linkWithText(title, link)
|
||||||
}
|
}
|
||||||
return title
|
return title
|
||||||
|
@ -167,6 +175,11 @@ class ArticleRenderer {
|
||||||
|
|
||||||
var d = [String: String]()
|
var d = [String: String]()
|
||||||
|
|
||||||
|
guard let article = article else {
|
||||||
|
assertionFailure("Article should have been set before calling this function.")
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
let title = titleOrTitleLink()
|
let title = titleOrTitleLink()
|
||||||
d["title"] = title
|
d["title"] = title
|
||||||
|
|
||||||
|
@ -220,10 +233,10 @@ class ArticleRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dateShouldBeLink() -> Bool {
|
private func dateShouldBeLink() -> Bool {
|
||||||
guard let permalink = article.url else {
|
guard let permalink = article?.url else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
guard let preferredLink = article.preferredLink else { // Title uses preferredLink
|
guard let preferredLink = article?.preferredLink else { // Title uses preferredLink
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return permalink != preferredLink // Make date a link if it’s a different link from the title’s link
|
return permalink != preferredLink // Make date a link if it’s a different link from the title’s link
|
||||||
|
@ -301,7 +314,7 @@ class ArticleRenderer {
|
||||||
|
|
||||||
// The author of this article, if just one.
|
// The author of this article, if just one.
|
||||||
|
|
||||||
if let authors = article.authors, authors.count == 1 {
|
if let authors = article?.authors, authors.count == 1 {
|
||||||
return authors.first!
|
return authors.first!
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -309,7 +322,7 @@ class ArticleRenderer {
|
||||||
|
|
||||||
private func singleFeedSpecifiedAuthor() -> Author? {
|
private func singleFeedSpecifiedAuthor() -> Author? {
|
||||||
|
|
||||||
if let authors = article.feed?.authors, authors.count == 1 {
|
if let authors = article?.feed?.authors, authors.count == 1 {
|
||||||
return authors.first!
|
return authors.first!
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -317,10 +330,10 @@ class ArticleRenderer {
|
||||||
|
|
||||||
private func feedAvatar() -> Avatar? {
|
private func feedAvatar() -> Avatar? {
|
||||||
|
|
||||||
guard let feedIconURL = article.feed?.iconURL else {
|
guard let feedIconURL = article?.feed?.iconURL else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return Avatar(imageURL: feedIconURL, url: article.feed?.homePageURL ?? article.feed?.url)
|
return Avatar(imageURL: feedIconURL, url: article?.feed?.homePageURL ?? article?.feed?.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func authorAvatar() -> Avatar? {
|
private func authorAvatar() -> Avatar? {
|
||||||
|
@ -354,8 +367,8 @@ class ArticleRenderer {
|
||||||
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
|
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
|
||||||
return Avatar(imageURL: imageURL, url: author.url)
|
return Avatar(imageURL: imageURL, url: author.url)
|
||||||
}
|
}
|
||||||
if let feedIconURL = article.feed?.iconURL {
|
if let feedIconURL = article?.feed?.iconURL {
|
||||||
return Avatar(imageURL: feedIconURL, url: article.feed?.homePageURL ?? article.feed?.url)
|
return Avatar(imageURL: feedIconURL, url: article?.feed?.homePageURL ?? article?.feed?.url)
|
||||||
}
|
}
|
||||||
if let author = singleFeedSpecifiedAuthor(), let imageURL = author.avatarURL {
|
if let author = singleFeedSpecifiedAuthor(), let imageURL = author.avatarURL {
|
||||||
return Avatar(imageURL: imageURL, url: author.url)
|
return Avatar(imageURL: imageURL, url: author.url)
|
||||||
|
@ -370,11 +383,11 @@ class ArticleRenderer {
|
||||||
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
|
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
|
||||||
return Avatar(imageURL: imageURL, url: author.url).html(dimension: avatarDimension)
|
return Avatar(imageURL: imageURL, url: author.url).html(dimension: avatarDimension)
|
||||||
}
|
}
|
||||||
if let feed = article.feed, let imgTag = feedIconImgTag(forFeed: feed) {
|
if let feed = article?.feed, let imgTag = feedIconImgTag(forFeed: feed) {
|
||||||
return imgTag
|
return imgTag
|
||||||
}
|
}
|
||||||
if let feedIconURL = article.feed?.iconURL {
|
if let feedIconURL = article?.feed?.iconURL {
|
||||||
return Avatar(imageURL: feedIconURL, url: article.feed?.homePageURL ?? article.feed?.url).html(dimension: avatarDimension)
|
return Avatar(imageURL: feedIconURL, url: article?.feed?.homePageURL ?? article?.feed?.url).html(dimension: avatarDimension)
|
||||||
}
|
}
|
||||||
if let author = singleFeedSpecifiedAuthor(), let imageURL = author.avatarURL {
|
if let author = singleFeedSpecifiedAuthor(), let imageURL = author.avatarURL {
|
||||||
return Avatar(imageURL: imageURL, url: author.url).html(dimension: avatarDimension)
|
return Avatar(imageURL: imageURL, url: author.url).html(dimension: avatarDimension)
|
||||||
|
@ -400,7 +413,7 @@ class ArticleRenderer {
|
||||||
|
|
||||||
private func byline() -> String {
|
private func byline() -> String {
|
||||||
|
|
||||||
guard let authors = article.authors ?? article.feed?.authors, !authors.isEmpty else {
|
guard let authors = article?.authors ?? article?.feed?.authors, !authors.isEmpty else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +421,7 @@ class ArticleRenderer {
|
||||||
// This code assumes that multiple authors would never match the feed name so that
|
// This code assumes that multiple authors would never match the feed name so that
|
||||||
// if there feed owner has an article co-author all authors are given the byline.
|
// if there feed owner has an article co-author all authors are given the byline.
|
||||||
if authors.count == 1, let author = authors.first {
|
if authors.count == 1, let author = authors.first {
|
||||||
if author.name == article.feed?.nameForDisplay {
|
if author.name == article?.feed?.nameForDisplay {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,7 +460,7 @@ class ArticleRenderer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func renderedHTML() -> String {
|
private func renderHTML(withBody body: String) -> String {
|
||||||
|
|
||||||
var s = "<!DOCTYPE html><html><head>\n\n"
|
var s = "<!DOCTYPE html><html><head>\n\n"
|
||||||
s += textInsideTag(title, "title")
|
s += textInsideTag(title, "title")
|
||||||
|
@ -480,7 +493,7 @@ class ArticleRenderer {
|
||||||
let appearanceClass = appearance?.isDarkMode ?? false ? "dark" : "light"
|
let appearanceClass = appearance?.isDarkMode ?? false ? "dark" : "light"
|
||||||
s += "\n\n</head><body id='bodyId' onload='startup()' class=\(appearanceClass)>\n\n"
|
s += "\n\n</head><body id='bodyId' onload='startup()' class=\(appearanceClass)>\n\n"
|
||||||
|
|
||||||
s += RSMacroProcessor.renderedText(withTemplate: template(), substitutions: substitutions(), macroStart: "[[", macroEnd: "]]")
|
s += body
|
||||||
|
|
||||||
s += "\n\n</body></html>"
|
s += "\n\n</body></html>"
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import RSWeb
|
||||||
final class DetailViewController: NSViewController, WKUIDelegate {
|
final class DetailViewController: NSViewController, WKUIDelegate {
|
||||||
|
|
||||||
@IBOutlet var containerView: DetailContainerView!
|
@IBOutlet var containerView: DetailContainerView!
|
||||||
@IBOutlet var noSelectionView: NoSelectionView!
|
|
||||||
|
|
||||||
var webview: DetailWebView!
|
var webview: DetailWebView!
|
||||||
|
|
||||||
|
@ -26,19 +25,13 @@ final class DetailViewController: NSViewController, WKUIDelegate {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
article = nil
|
article = nil
|
||||||
if let _ = articles {
|
reloadHTML()
|
||||||
noSelectionView.showMultipleSelection()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
noSelectionView.showNoSelection()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var article: Article? {
|
private var article: Article? {
|
||||||
didSet {
|
didSet {
|
||||||
reloadHTML()
|
reloadHTML()
|
||||||
showOrHideWebView()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,9 +71,10 @@ final class DetailViewController: NSViewController, WKUIDelegate {
|
||||||
webview.customUserAgent = userAgent
|
webview.customUserAgent = userAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reloadHTML()
|
||||||
|
containerView.contentView = webview
|
||||||
containerView.viewController = self
|
containerView.viewController = self
|
||||||
|
|
||||||
showOrHideWebView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Scrolling
|
// MARK: - Scrolling
|
||||||
|
@ -194,35 +188,21 @@ private extension DetailViewController {
|
||||||
|
|
||||||
func reloadHTML() {
|
func reloadHTML() {
|
||||||
|
|
||||||
if let article = article {
|
|
||||||
let articleRenderer = ArticleRenderer(article: article,
|
let articleRenderer = ArticleRenderer(article: article,
|
||||||
style: ArticleStylesManager.shared.currentStyle,
|
style: ArticleStylesManager.shared.currentStyle,
|
||||||
appearance: self.view.effectiveAppearance)
|
appearance: self.view.effectiveAppearance)
|
||||||
webview.loadHTMLString(articleRenderer.html, baseURL: articleRenderer.baseURL)
|
|
||||||
|
if article != nil {
|
||||||
|
webview.loadHTMLString(articleRenderer.articleHTML, baseURL: articleRenderer.baseURL)
|
||||||
|
}
|
||||||
|
else if articles != nil {
|
||||||
|
webview.loadHTMLString(articleRenderer.multipleSelectionHTML, baseURL: nil)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
webview.loadHTMLString("", baseURL: nil)
|
webview.loadHTMLString(articleRenderer.noSelectionHTML, baseURL: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showOrHideWebView() {
|
|
||||||
|
|
||||||
if let _ = article {
|
|
||||||
switchToView(webview)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
switchToView(noSelectionView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func switchToView(_ view: NSView) {
|
|
||||||
|
|
||||||
if containerView.contentView == view {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
containerView.contentView = view
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) {
|
func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) {
|
||||||
|
|
||||||
let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x"
|
let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x"
|
||||||
|
@ -251,12 +231,6 @@ final class DetailContainerView: NSView {
|
||||||
|
|
||||||
weak var viewController: DetailViewController? = nil
|
weak var viewController: DetailViewController? = nil
|
||||||
|
|
||||||
// private var didConfigureLayer = false
|
|
||||||
//
|
|
||||||
// override var wantsUpdateLayer: Bool {
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
var contentView: NSView? {
|
var contentView: NSView? {
|
||||||
didSet {
|
didSet {
|
||||||
if let oldContentView = oldValue {
|
if let oldContentView = oldValue {
|
||||||
|
@ -284,37 +258,8 @@ final class DetailContainerView: NSView {
|
||||||
NSColor.textBackgroundColor.setFill()
|
NSColor.textBackgroundColor.setFill()
|
||||||
dirtyRect.fill()
|
dirtyRect.fill()
|
||||||
}
|
}
|
||||||
// override func updateLayer() {
|
|
||||||
//
|
|
||||||
// guard !didConfigureLayer else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// if let layer = layer {
|
|
||||||
// let color = appDelegate.currentTheme.color(forKey: "MainWindow.Detail.backgroundColor")
|
|
||||||
// layer.backgroundColor = color.cgColor
|
|
||||||
// didConfigureLayer = true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: -
|
|
||||||
|
|
||||||
final class NoSelectionView: NSView {
|
|
||||||
|
|
||||||
@IBOutlet var noSelectionLabel: NSTextField!
|
|
||||||
@IBOutlet var multipleSelectionLabel: NSTextField!
|
|
||||||
|
|
||||||
func showMultipleSelection() {
|
|
||||||
|
|
||||||
noSelectionLabel.isHidden = true
|
|
||||||
multipleSelectionLabel.isHidden = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func showNoSelection() {
|
|
||||||
|
|
||||||
noSelectionLabel.isHidden = false
|
|
||||||
multipleSelectionLabel.isHidden = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
|
@ -21,6 +21,13 @@ a:hover {
|
||||||
height: 68px;
|
height: 68px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.systemMessage {
|
||||||
|
position: absolute;
|
||||||
|
top: 45%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-55%) translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
/* Light mode */
|
/* Light mode */
|
||||||
|
|
||||||
body.light {
|
body.light {
|
||||||
|
@ -44,6 +51,10 @@ body.light .articleDateline, body.light .articleDateLine.a:link, body.light .art
|
||||||
color: rgba(0, 0, 0, 0.3);
|
color: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.light > .systemMessage {
|
||||||
|
color: #cbcbcb;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dark mode */
|
/* Dark mode */
|
||||||
|
|
||||||
body.dark {
|
body.dark {
|
||||||
|
@ -70,6 +81,10 @@ body.dark .articleDateline, body.dark .articleDateLine.a:link, body.dark .articl
|
||||||
color: #d2d2d2;
|
color: #d2d2d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark > .systemMessage {
|
||||||
|
color: #5f5f5f;
|
||||||
|
}
|
||||||
|
|
||||||
.feedlink a:link, .feedlink a:visited {
|
.feedlink a:link, .feedlink a:visited {
|
||||||
color: rgba(0, 0, 0, 0.6);
|
color: rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ extension Article: PasteboardWriterOwner {
|
||||||
|
|
||||||
private lazy var renderedHTML: String = {
|
private lazy var renderedHTML: String = {
|
||||||
let articleRenderer = ArticleRenderer(article: article, style: ArticleStylesManager.shared.currentStyle)
|
let articleRenderer = ArticleRenderer(article: article, style: ArticleStylesManager.shared.currentStyle)
|
||||||
return articleRenderer.html
|
return articleRenderer.articleHTML
|
||||||
}()
|
}()
|
||||||
|
|
||||||
init(article: Article) {
|
init(article: Article) {
|
||||||
|
|
|
@ -127,11 +127,6 @@
|
||||||
</dict>
|
</dict>
|
||||||
<key>Detail</key>
|
<key>Detail</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>noSelectionView</key>
|
|
||||||
<dict>
|
|
||||||
<key>backgroundColor</key>
|
|
||||||
<string>FFFFFF</string>
|
|
||||||
</dict>
|
|
||||||
<key>statusBar</key>
|
<key>statusBar</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>backgroundColor</key>
|
<key>backgroundColor</key>
|
||||||
|
|
Loading…
Reference in New Issue