fix(mobile): improve layout and styling consistency across components
- Adjusted padding in EntryTitle and EntryDetailScreen for uniformity. - Updated HTML component to enhance structure and readability. - Modified CSS classes in HTML and image components for better alignment. - Cleaned up link component styles to remove unnecessary classes. These changes enhance the overall user interface and maintain a consistent design throughout the application. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
c7afad6b27
commit
017d9864cd
|
|
@ -23,7 +23,6 @@ class FOWebView: WKWebView {
|
|||
if #available(iOS 16.4, *) {
|
||||
isInspectable = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var state: WebViewState!
|
||||
|
|
@ -39,46 +38,45 @@ class FOWebView: WKWebView {
|
|||
navigationDelegate = self
|
||||
uiDelegate = self
|
||||
}
|
||||
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
private class FOWKWebViewConfiguration: WKWebViewConfiguration {
|
||||
static public let shared = FOWKWebViewConfiguration()
|
||||
public static let shared = FOWKWebViewConfiguration()
|
||||
override init() {
|
||||
super.init()
|
||||
let configuration = self
|
||||
|
||||
let hexAccentColor = Utils.accentColor.toHex()
|
||||
let css = """
|
||||
:root { overflow: hidden !important; overflow-behavior: none !important; }
|
||||
body {
|
||||
overflow-y: visible !important;
|
||||
position: absolute !important;
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
-webkit-overflow-scrolling: touch !important;
|
||||
}
|
||||
::selection {
|
||||
background-color: \(hexAccentColor) !important;
|
||||
}
|
||||
"""
|
||||
:root { overflow: hidden !important; overflow-behavior: none !important; }
|
||||
body {
|
||||
overflow-y: visible !important;
|
||||
position: absolute !important;
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
-webkit-overflow-scrolling: touch !important;
|
||||
}
|
||||
::selection {
|
||||
background-color: \(hexAccentColor) !important;
|
||||
}
|
||||
"""
|
||||
|
||||
let script = WKUserScript(
|
||||
_ = WKUserScript(
|
||||
source: """
|
||||
var style = document.createElement('style');
|
||||
style.textContent = '\(css)';
|
||||
document.head.appendChild(style);
|
||||
""",
|
||||
var style = document.createElement('style');
|
||||
style.textContent = '\(css)';
|
||||
document.head.appendChild(style);
|
||||
""",
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: true
|
||||
)
|
||||
|
||||
let atStartScripts = WKWebView.loadInjectedJs(forResource: "at_start")
|
||||
|
||||
|
||||
|
||||
if let jsString = atStartScripts {
|
||||
let script = WKUserScript(
|
||||
|
|
@ -104,54 +102,54 @@ private class FOWKWebViewConfiguration: WKWebViewConfiguration {
|
|||
|
||||
let schemeHandler = FollowImageURLSchemeHandler()
|
||||
configuration.setURLSchemeHandler(
|
||||
schemeHandler, forURLScheme: FollowImageURLSchemeHandler.rewriteScheme)
|
||||
schemeHandler, forURLScheme: FollowImageURLSchemeHandler.rewriteScheme
|
||||
)
|
||||
|
||||
let customSchemeScript = WKUserScript(
|
||||
source: """
|
||||
(function() {
|
||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...args) {
|
||||
const modifiedUrl = url.replace(/^https?:/, '\(FollowImageURLSchemeHandler.rewriteScheme):');
|
||||
originalXHROpen.call(this, method, modifiedUrl, ...args);
|
||||
};
|
||||
(function() {
|
||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...args) {
|
||||
const modifiedUrl = url.replace(/^https?:/, '\(FollowImageURLSchemeHandler.rewriteScheme):');
|
||||
originalXHROpen.call(this, method, modifiedUrl, ...args);
|
||||
};
|
||||
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = function(url, options) {
|
||||
const modifiedUrl = url.replace(/^https?:/, '\(FollowImageURLSchemeHandler.rewriteScheme):');
|
||||
return originalFetch(modifiedUrl, options);
|
||||
};
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = function(url, options) {
|
||||
const modifiedUrl = url.replace(/^https?:/, '\(FollowImageURLSchemeHandler.rewriteScheme):');
|
||||
return originalFetch(modifiedUrl, options);
|
||||
};
|
||||
|
||||
const originalImageSrc = Object.getOwnPropertyDescriptor(Image.prototype, 'src');
|
||||
Object.defineProperty(Image.prototype, 'src', {
|
||||
set: function(url) {
|
||||
const modifiedUrl = url.replace(/^https?:/, '\(FollowImageURLSchemeHandler.rewriteScheme):');
|
||||
originalImageSrc.set.call(this, modifiedUrl);
|
||||
}
|
||||
});
|
||||
})();
|
||||
""",
|
||||
const originalImageSrc = Object.getOwnPropertyDescriptor(Image.prototype, 'src');
|
||||
Object.defineProperty(Image.prototype, 'src', {
|
||||
set: function(url) {
|
||||
const modifiedUrl = url.replace(/^https?:/, '\(FollowImageURLSchemeHandler.rewriteScheme):');
|
||||
originalImageSrc.set.call(this, modifiedUrl);
|
||||
}
|
||||
});
|
||||
})();
|
||||
""",
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: false
|
||||
)
|
||||
configuration.userContentController.addUserScript(customSchemeScript)
|
||||
|
||||
configuration.userContentController.addUserScript(script2)
|
||||
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
extension WKWebView {
|
||||
|
||||
fileprivate static func loadInjectedJs(forResource: String) -> String? {
|
||||
private extension WKWebView {
|
||||
static func loadInjectedJs(forResource: String) -> String? {
|
||||
if let bundleURL = Bundle(for: WebViewView.self).url(
|
||||
forResource: "js", withExtension: "bundle"),
|
||||
forResource: "js", withExtension: "bundle"
|
||||
),
|
||||
let resourceBundle = Bundle(url: bundleURL)
|
||||
{
|
||||
|
||||
if let jsPath = resourceBundle.path(forResource: forResource, ofType: "js") {
|
||||
do {
|
||||
let initJsContent = try String(contentsOfFile: jsPath, encoding: .utf8)
|
||||
|
|
@ -161,15 +159,12 @@ extension WKWebView {
|
|||
print("Error reading JS file:", error)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate {
|
||||
|
||||
func userContentController(
|
||||
_ userContentController: WKUserContentController, didReceive message: WKScriptMessage
|
||||
) {
|
||||
|
|
@ -184,7 +179,8 @@ extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
|||
switch data.type {
|
||||
case "setContentHeight":
|
||||
let data = try? JSONDecoder().decode(
|
||||
SetContentHeightPayload.self, from: decode)
|
||||
SetContentHeightPayload.self, from: decode
|
||||
)
|
||||
guard let data = data else { return }
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -192,11 +188,12 @@ extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
|||
}
|
||||
|
||||
case "measure":
|
||||
self.measureWebView(SharedWebViewModule.sharedWebView!)
|
||||
measureWebView(SharedWebViewModule.sharedWebView!)
|
||||
|
||||
case "previewImage":
|
||||
let data = try? JSONDecoder().decode(
|
||||
PreviewImagePayload.self, from: decode)
|
||||
PreviewImagePayload.self, from: decode
|
||||
)
|
||||
|
||||
guard let data = data else { return }
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -209,15 +206,13 @@ extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
|||
default:
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func measureWebView(_ webView: WKWebView) {
|
||||
let jsCode = "document.querySelector('#root').scrollHeight"
|
||||
webView.evaluateJavaScript(jsCode) { (height, error) in
|
||||
webView.evaluateJavaScript(jsCode) { height, _ in
|
||||
if let height = height as? CGFloat, height > 0 {
|
||||
DispatchQueue.main.async {
|
||||
self.state.contentHeight = height
|
||||
|
|
@ -233,7 +228,6 @@ extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
|||
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in
|
||||
self?.measureWebView(webView)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func webView(
|
||||
|
|
@ -241,7 +235,7 @@ extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
|||
for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures
|
||||
) -> WKWebView? {
|
||||
if let url = navigationAction.request.url,
|
||||
let viewController = Utils.getRootVC()
|
||||
let viewController = Utils.getRootVC()
|
||||
{
|
||||
WebViewManager.presentModalWebView(url: url, from: viewController)
|
||||
}
|
||||
|
|
@ -254,7 +248,7 @@ extension FOWebView: WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
|||
) {
|
||||
if navigationAction.targetFrame == nil {
|
||||
if let url = navigationAction.request.url,
|
||||
let viewController = Utils.getRootVC()
|
||||
let viewController = Utils.getRootVC()
|
||||
{
|
||||
WebViewManager.presentModalWebView(url: url, from: viewController)
|
||||
decisionHandler(.cancel)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export const EntryTitle = ({ title, entryId }: { title: string; entryId: string
|
|||
}}
|
||||
>
|
||||
<EntryTranslation
|
||||
className="text-label px-4 text-4xl font-bold leading-snug"
|
||||
className="text-label px-5 text-4xl font-bold leading-snug"
|
||||
source={title}
|
||||
target={translation?.title}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ const EntryInfo = ({ entryId }: { entryId: string }) => {
|
|||
const { publishedAt } = entry
|
||||
|
||||
return (
|
||||
<View className="mt-4 flex flex-row items-center gap-4 px-4">
|
||||
<View className="mt-4 flex flex-row items-center gap-4 px-5">
|
||||
{feed && (
|
||||
<View className="flex shrink flex-row items-center gap-2">
|
||||
<FeedIcon feed={feed} />
|
||||
|
|
|
|||
|
|
@ -40,11 +40,9 @@ export const App = () => {
|
|||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<HTML
|
||||
children={entry?.content}
|
||||
renderInlineStyle={readerRenderInlineStyle}
|
||||
noMedia={noMedia}
|
||||
/>
|
||||
<HTML renderInlineStyle={readerRenderInlineStyle} noMedia={noMedia}>
|
||||
{entry?.content}
|
||||
</HTML>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const HTML = <A extends keyof JSX.IntrinsicElements = "div">(props: HTMLP
|
|||
{
|
||||
...rest,
|
||||
ref: setRefElement,
|
||||
className: clsx("prose mx-auto px-3", "dark:prose-invert"),
|
||||
className: clsx("prose mx-auto px-5 pb-8", "dark:prose-invert"),
|
||||
},
|
||||
markdownElement,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export const MarkdownImage = (props: HTMLProps<"img">) => {
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="relative -mx-3 overflow-hidden bg-gray-300 dark:bg-neutral-800"
|
||||
className="relative -mx-5 overflow-hidden bg-gray-300 dark:bg-neutral-800"
|
||||
style={{
|
||||
width: scaleWidth || undefined,
|
||||
height: scaleHeight || undefined,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const MarkdownLink = (props: LinkProps) => {
|
|||
<TooltipTrigger asChild>
|
||||
<a
|
||||
draggable="false"
|
||||
className="follow-link--underline text-foreground font-semibold no-underline"
|
||||
className="text-foreground font-semibold no-underline"
|
||||
href={populatedFullHref}
|
||||
title={props.title}
|
||||
target="_blank"
|
||||
|
|
|
|||
Loading…
Reference in New Issue