diff --git a/Gemini-iOS/AppDelegate.swift b/Gemini-iOS/AppDelegate.swift index 1ec0c8c..93de494 100644 --- a/Gemini-iOS/AppDelegate.swift +++ b/Gemini-iOS/AppDelegate.swift @@ -13,7 +13,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + SymbolCache.load() + return true } diff --git a/Gemini-iOS/BrowserWebViewController.swift b/Gemini-iOS/BrowserWebViewController.swift index b72f1c2..314ffce 100644 --- a/Gemini-iOS/BrowserWebViewController.swift +++ b/Gemini-iOS/BrowserWebViewController.swift @@ -40,6 +40,26 @@ class BrowserWebViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + let documentURL = self.url + renderer.linkPrefix = { (url: URL) -> String in + let symbolClass: String + if url.scheme == "gemini" { + if url.host == documentURL.host { + symbolClass = "arrow-right" + } else { + symbolClass = "link" + } + } else if url.scheme == "http" || url.scheme == "https" { + symbolClass = "safari" + } else if url.scheme == "mailto" { + symbolClass = "envelope" + } else { + symbolClass = "arrow-up-left-square" + } + return "" + + } + view.backgroundColor = .systemBackground webView = WKWebView() @@ -163,10 +183,17 @@ class BrowserWebViewController: UIViewController { + """ + private static let symbolStyles = SymbolCache.symbols.map { (k, v) in + ".symbol.\(k.replacingOccurrences(of: ".", with: "-")) { background-image: url(\"data:image/png;base64,\(v)\"); }" + }.joined(separator: "\n") + private static let postamble = """ diff --git a/Gemini-iOS/Resources/browser.css b/Gemini-iOS/Resources/browser.css index d4951ee..951f54f 100644 --- a/Gemini-iOS/Resources/browser.css +++ b/Gemini-iOS/Resources/browser.css @@ -17,7 +17,7 @@ h1, h2, h3 { p.link { display: block; - margin: 8px 0; + margin: 4px 0; } a { @@ -28,6 +28,17 @@ ul { padding-left: 20px; } +.symbol { + display: inline-block; + float: left; + width: 1.25em; + height: 1.25em; + margin-right: 0.25em; + background-size: contain; + background-repeat: no-repeat; + vertical-align: middle; +} + @media (prefers-color-scheme: dark) { body { background-color: black; @@ -37,4 +48,8 @@ ul { a { color: rgb(10, 132, 255); } + + .symbol { + filter: invert(100%); + } } diff --git a/Gemini-iOS/SymbolCache.swift b/Gemini-iOS/SymbolCache.swift new file mode 100644 index 0000000..65da108 --- /dev/null +++ b/Gemini-iOS/SymbolCache.swift @@ -0,0 +1,33 @@ +// +// SymbolCache.swift +// Gemini-iOS +// +// Created by Shadowfacts on 12/17/20. +// + +import UIKit + +struct SymbolCache { + + private(set) static var symbols = [String: String]() + + private static let defaultSymbols = [ + "arrow.right", + "link", + "safari", + "envelope", + "arrow.up.left.square", + ] + + static func load() { + defaultSymbols.forEach { loadSymbol(name: $0) } + } + + private static func loadSymbol(name: String) { + let config = UIImage.SymbolConfiguration(pointSize: 16) + let symbol = UIImage(systemName: name, withConfiguration: config)! + let data = symbol.pngData()! + symbols[name] = data.base64EncodedString() + } + +} diff --git a/Gemini.xcodeproj/project.pbxproj b/Gemini.xcodeproj/project.pbxproj index 8570c16..df7d6ea 100644 --- a/Gemini.xcodeproj/project.pbxproj +++ b/Gemini.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ D688F621258B0811003A0A73 /* BrowserNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F620258B0811003A0A73 /* BrowserNavigationController.swift */; }; D688F62A258B0833003A0A73 /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F629258B0833003A0A73 /* InteractivePushTransition.swift */; }; D688F633258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */; }; + D688F64A258C17F3003A0A73 /* SymbolCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F649258C17F3003A0A73 /* SymbolCache.swift */; }; D691A64E25217C6F00348C4B /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A64D25217C6F00348C4B /* Preferences.swift */; }; D691A66725217FD800348C4B /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A66625217FD800348C4B /* PreferencesView.swift */; }; D691A68725223A4700348C4B /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A68625223A4600348C4B /* NavigationBar.swift */; }; @@ -311,6 +312,7 @@ D688F620258B0811003A0A73 /* BrowserNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserNavigationController.swift; sourceTree = ""; }; D688F629258B0833003A0A73 /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = ""; }; D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = ""; }; + D688F649258C17F3003A0A73 /* SymbolCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolCache.swift; sourceTree = ""; }; D691A64D25217C6F00348C4B /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; D691A66625217FD800348C4B /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = ""; }; D691A6762522382E00348C4B /* BrowserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserViewController.swift; sourceTree = ""; }; @@ -578,6 +580,7 @@ children = ( D6E152A424BFFDF500FDF9D3 /* AppDelegate.swift */, D6E152A624BFFDF500FDF9D3 /* SceneDelegate.swift */, + D688F649258C17F3003A0A73 /* SymbolCache.swift */, D688F620258B0811003A0A73 /* BrowserNavigationController.swift */, D688F629258B0833003A0A73 /* InteractivePushTransition.swift */, D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */, @@ -1108,6 +1111,7 @@ D6E152A524BFFDF500FDF9D3 /* AppDelegate.swift in Sources */, D691A6A0252242FC00348C4B /* ToolBar.swift in Sources */, D6E152A724BFFDF500FDF9D3 /* SceneDelegate.swift in Sources */, + D688F64A258C17F3003A0A73 /* SymbolCache.swift in Sources */, D62BCEE2252553620031D894 /* ActivityView.swift in Sources */, D691A68725223A4700348C4B /* NavigationBar.swift in Sources */, D691A64E25217C6F00348C4B /* Preferences.swift in Sources */, diff --git a/GeminiRenderer/GeminiHTMLRenderer.swift b/GeminiRenderer/GeminiHTMLRenderer.swift index c29d629..df905ee 100644 --- a/GeminiRenderer/GeminiHTMLRenderer.swift +++ b/GeminiRenderer/GeminiHTMLRenderer.swift @@ -9,13 +9,9 @@ import Foundation import GeminiFormat import HTMLEntities -public protocol GeminiHTMLRendererDelegate: class { - -} - public class GeminiHTMLRenderer { - public weak var delegate: GeminiHTMLRendererDelegate? + public var linkPrefix: ((URL) -> String?)? public init() { } @@ -36,7 +32,8 @@ public class GeminiHTMLRenderer { str += "

\(text.htmlEscape())

" case let .link(url, text: maybeText): let text = maybeText ?? url.absoluteString - str += "

\(text.htmlEscape())

" + let linkPrefix = self.linkPrefix?(url) ?? "" + str += "

\(linkPrefix)\(text.htmlEscape())

" case .preformattedToggle(alt: _): inPreformatting = !inPreformatting if inPreformatting {