Add link decorations
This commit is contained in:
parent
2d60f733c3
commit
314d8cf82c
|
@ -13,7 +13,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
// Override point for customization after application launch.
|
SymbolCache.load()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,26 @@ class BrowserWebViewController: UIViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.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 "<span class=\"symbol \(symbolClass)\" aria-hidden=\"true\"></span>"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
view.backgroundColor = .systemBackground
|
view.backgroundColor = .systemBackground
|
||||||
|
|
||||||
webView = WKWebView()
|
webView = WKWebView()
|
||||||
|
@ -163,10 +183,17 @@ class BrowserWebViewController: UIViewController {
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<link rel="stylesheet" href="\(Bundle.main.url(forResource: "browser", withExtension: "css")!.absoluteString)">
|
<link rel="stylesheet" href="\(Bundle.main.url(forResource: "browser", withExtension: "css")!.absoluteString)">
|
||||||
|
<style>
|
||||||
|
\(symbolStyles)
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
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 = """
|
private static let postamble = """
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -17,7 +17,7 @@ h1, h2, h3 {
|
||||||
|
|
||||||
p.link {
|
p.link {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 8px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -28,6 +28,17 @@ ul {
|
||||||
padding-left: 20px;
|
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) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body {
|
body {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
|
@ -37,4 +48,8 @@ ul {
|
||||||
a {
|
a {
|
||||||
color: rgb(10, 132, 255);
|
color: rgb(10, 132, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.symbol {
|
||||||
|
filter: invert(100%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -47,6 +47,7 @@
|
||||||
D688F621258B0811003A0A73 /* BrowserNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F620258B0811003A0A73 /* BrowserNavigationController.swift */; };
|
D688F621258B0811003A0A73 /* BrowserNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F620258B0811003A0A73 /* BrowserNavigationController.swift */; };
|
||||||
D688F62A258B0833003A0A73 /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F629258B0833003A0A73 /* InteractivePushTransition.swift */; };
|
D688F62A258B0833003A0A73 /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F629258B0833003A0A73 /* InteractivePushTransition.swift */; };
|
||||||
D688F633258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.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 */; };
|
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A64D25217C6F00348C4B /* Preferences.swift */; };
|
||||||
D691A66725217FD800348C4B /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A66625217FD800348C4B /* PreferencesView.swift */; };
|
D691A66725217FD800348C4B /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A66625217FD800348C4B /* PreferencesView.swift */; };
|
||||||
D691A68725223A4700348C4B /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D691A68625223A4600348C4B /* NavigationBar.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 = "<group>"; };
|
D688F620258B0811003A0A73 /* BrowserNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserNavigationController.swift; sourceTree = "<group>"; };
|
||||||
D688F629258B0833003A0A73 /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; };
|
D688F629258B0833003A0A73 /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; };
|
||||||
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||||
|
D688F649258C17F3003A0A73 /* SymbolCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolCache.swift; sourceTree = "<group>"; };
|
||||||
D691A64D25217C6F00348C4B /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
D691A64D25217C6F00348C4B /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
||||||
D691A66625217FD800348C4B /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
D691A66625217FD800348C4B /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
||||||
D691A6762522382E00348C4B /* BrowserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserViewController.swift; sourceTree = "<group>"; };
|
D691A6762522382E00348C4B /* BrowserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -578,6 +580,7 @@
|
||||||
children = (
|
children = (
|
||||||
D6E152A424BFFDF500FDF9D3 /* AppDelegate.swift */,
|
D6E152A424BFFDF500FDF9D3 /* AppDelegate.swift */,
|
||||||
D6E152A624BFFDF500FDF9D3 /* SceneDelegate.swift */,
|
D6E152A624BFFDF500FDF9D3 /* SceneDelegate.swift */,
|
||||||
|
D688F649258C17F3003A0A73 /* SymbolCache.swift */,
|
||||||
D688F620258B0811003A0A73 /* BrowserNavigationController.swift */,
|
D688F620258B0811003A0A73 /* BrowserNavigationController.swift */,
|
||||||
D688F629258B0833003A0A73 /* InteractivePushTransition.swift */,
|
D688F629258B0833003A0A73 /* InteractivePushTransition.swift */,
|
||||||
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */,
|
D688F632258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift */,
|
||||||
|
@ -1108,6 +1111,7 @@
|
||||||
D6E152A524BFFDF500FDF9D3 /* AppDelegate.swift in Sources */,
|
D6E152A524BFFDF500FDF9D3 /* AppDelegate.swift in Sources */,
|
||||||
D691A6A0252242FC00348C4B /* ToolBar.swift in Sources */,
|
D691A6A0252242FC00348C4B /* ToolBar.swift in Sources */,
|
||||||
D6E152A724BFFDF500FDF9D3 /* SceneDelegate.swift in Sources */,
|
D6E152A724BFFDF500FDF9D3 /* SceneDelegate.swift in Sources */,
|
||||||
|
D688F64A258C17F3003A0A73 /* SymbolCache.swift in Sources */,
|
||||||
D62BCEE2252553620031D894 /* ActivityView.swift in Sources */,
|
D62BCEE2252553620031D894 /* ActivityView.swift in Sources */,
|
||||||
D691A68725223A4700348C4B /* NavigationBar.swift in Sources */,
|
D691A68725223A4700348C4B /* NavigationBar.swift in Sources */,
|
||||||
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */,
|
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */,
|
||||||
|
|
|
@ -9,13 +9,9 @@ import Foundation
|
||||||
import GeminiFormat
|
import GeminiFormat
|
||||||
import HTMLEntities
|
import HTMLEntities
|
||||||
|
|
||||||
public protocol GeminiHTMLRendererDelegate: class {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GeminiHTMLRenderer {
|
public class GeminiHTMLRenderer {
|
||||||
|
|
||||||
public weak var delegate: GeminiHTMLRendererDelegate?
|
public var linkPrefix: ((URL) -> String?)?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
}
|
}
|
||||||
|
@ -36,7 +32,8 @@ public class GeminiHTMLRenderer {
|
||||||
str += "<p>\(text.htmlEscape())</p>"
|
str += "<p>\(text.htmlEscape())</p>"
|
||||||
case let .link(url, text: maybeText):
|
case let .link(url, text: maybeText):
|
||||||
let text = maybeText ?? url.absoluteString
|
let text = maybeText ?? url.absoluteString
|
||||||
str += "<p class=\"link\"><a href=\"\(url.absoluteString)\">\(text.htmlEscape())</a></p>"
|
let linkPrefix = self.linkPrefix?(url) ?? ""
|
||||||
|
str += "<p class=\"link\">\(linkPrefix)<a href=\"\(url.absoluteString)\">\(text.htmlEscape())</a></p>"
|
||||||
case .preformattedToggle(alt: _):
|
case .preformattedToggle(alt: _):
|
||||||
inPreformatting = !inPreformatting
|
inPreformatting = !inPreformatting
|
||||||
if inPreformatting {
|
if inPreformatting {
|
||||||
|
|
Loading…
Reference in New Issue