Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4eb3e0313 | |||
| 0a17d113a4 | |||
| 3b39d1898a | |||
| 97c1c2a0e8 | |||
| 95478f2db4 | |||
| 4d5c67c2ea |
@@ -11,6 +11,7 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-filesystem')
|
||||
implementation project(':capacitor-keyboard')
|
||||
implementation project(':capacitor-local-notifications')
|
||||
implementation project(':capacitor-share')
|
||||
implementation project(':capacitor-status-bar')
|
||||
|
||||
@@ -8,6 +8,9 @@ project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/
|
||||
include ':capacitor-filesystem'
|
||||
project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
|
||||
|
||||
include ':capacitor-keyboard'
|
||||
project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
|
||||
|
||||
include ':capacitor-local-notifications'
|
||||
project(':capacitor-local-notifications').projectDir = new File('../node_modules/@capacitor/local-notifications/android')
|
||||
|
||||
|
||||
+6
-1
@@ -19,7 +19,12 @@ const config: CapacitorConfig = {
|
||||
backgroundColor: '#14161f',
|
||||
contentInset: 'never',
|
||||
scheme: 'Ditto'
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
Keyboard: {
|
||||
resizeOnFullScreen: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -14,6 +14,7 @@ let package = Package(
|
||||
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.2.0"),
|
||||
.package(name: "CapacitorApp", path: "../../../node_modules/@capacitor/app"),
|
||||
.package(name: "CapacitorFilesystem", path: "../../../node_modules/@capacitor/filesystem"),
|
||||
.package(name: "CapacitorKeyboard", path: "../../../node_modules/@capacitor/keyboard"),
|
||||
.package(name: "CapacitorLocalNotifications", path: "../../../node_modules/@capacitor/local-notifications"),
|
||||
.package(name: "CapacitorShare", path: "../../../node_modules/@capacitor/share"),
|
||||
.package(name: "CapacitorStatusBar", path: "../../../node_modules/@capacitor/status-bar")
|
||||
@@ -26,6 +27,7 @@ let package = Package(
|
||||
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
||||
.product(name: "CapacitorApp", package: "CapacitorApp"),
|
||||
.product(name: "CapacitorFilesystem", package: "CapacitorFilesystem"),
|
||||
.product(name: "CapacitorKeyboard", package: "CapacitorKeyboard"),
|
||||
.product(name: "CapacitorLocalNotifications", package: "CapacitorLocalNotifications"),
|
||||
.product(name: "CapacitorShare", package: "CapacitorShare"),
|
||||
.product(name: "CapacitorStatusBar", package: "CapacitorStatusBar")
|
||||
|
||||
Generated
+10
@@ -11,6 +11,7 @@
|
||||
"@capacitor/app": "^8.0.0",
|
||||
"@capacitor/core": "^8.1.0",
|
||||
"@capacitor/filesystem": "^8.1.2",
|
||||
"@capacitor/keyboard": "^8.0.2",
|
||||
"@capacitor/local-notifications": "^8.0.1",
|
||||
"@capacitor/share": "^8.0.1",
|
||||
"@capacitor/status-bar": "^8.0.0",
|
||||
@@ -379,6 +380,15 @@
|
||||
"@capacitor/core": "^8.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/keyboard": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-8.0.2.tgz",
|
||||
"integrity": "sha512-he6xKmTBp5AhVrWJeEi6RYkJ25FjLLdNruBU2wafpITk3Nb7UdzOj96x3K6etFuEj8/rtn9WXBTs1o2XA86A1A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/local-notifications": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/local-notifications/-/local-notifications-8.0.1.tgz",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"@capacitor/app": "^8.0.0",
|
||||
"@capacitor/core": "^8.1.0",
|
||||
"@capacitor/filesystem": "^8.1.2",
|
||||
"@capacitor/keyboard": "^8.0.2",
|
||||
"@capacitor/local-notifications": "^8.0.1",
|
||||
"@capacitor/share": "^8.0.1",
|
||||
"@capacitor/status-bar": "^8.0.0",
|
||||
|
||||
@@ -40,8 +40,8 @@ export function MobileBottomNav() {
|
||||
setSearchOpen((v) => !v);
|
||||
}, []);
|
||||
|
||||
// Keep the nav visible while search is open regardless of scroll
|
||||
const isHidden = hidden && !searchOpen;
|
||||
// Hide the nav when search sheet is open so it doesn't compete for space
|
||||
const isHidden = hidden || searchOpen;
|
||||
|
||||
const displayName = metadata?.name || metadata?.display_name;
|
||||
const isOnProfile = user && location.pathname === profileUrl;
|
||||
|
||||
@@ -101,6 +101,28 @@ export function MobileSearchSheet({ open, onClose }: MobileSearchSheetProps) {
|
||||
const wikipediaIndex = hasWikipedia ? nextMobileIdx++ : -1;
|
||||
const archiveIndex = hasArchive ? nextMobileIdx++ : -1;
|
||||
|
||||
// Lock body scroll while the search sheet is open.
|
||||
// overflow:hidden alone is unreliable on mobile Safari, so we also
|
||||
// block touchmove on the document (except inside the results scroller).
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const prevOverflow = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
const preventScroll = (e: TouchEvent) => {
|
||||
// Allow scrolling inside the results list
|
||||
const target = e.target as HTMLElement;
|
||||
if (target.closest?.('[data-mobile-search-results]')) return;
|
||||
e.preventDefault();
|
||||
};
|
||||
document.addEventListener('touchmove', preventScroll, { passive: false });
|
||||
|
||||
return () => {
|
||||
document.body.style.overflow = prevOverflow;
|
||||
document.removeEventListener('touchmove', preventScroll);
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
// Focus input when opened
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
@@ -224,8 +246,8 @@ export function MobileSearchSheet({ open, onClose }: MobileSearchSheetProps) {
|
||||
onClick={handleClose}
|
||||
/>
|
||||
|
||||
{/* Bottom sheet — sits above the bottom nav bar */}
|
||||
<div className="fixed left-0 right-0 z-[49] sidebar:hidden animate-in slide-in-from-bottom-4 duration-200 bottom-mobile-nav">
|
||||
{/* Bottom sheet — sits at the bottom of the screen with safe area clearance */}
|
||||
<div className="fixed left-0 right-0 bottom-0 z-[49] sidebar:hidden animate-in slide-in-from-bottom-4 duration-200 pb-6">
|
||||
|
||||
{/* Results list — reversed so closest to input = most relevant */}
|
||||
{hasResults && (
|
||||
@@ -293,7 +315,7 @@ export function MobileSearchSheet({ open, onClose }: MobileSearchSheetProps) {
|
||||
)}
|
||||
|
||||
{/* Input bar */}
|
||||
<div className="flex items-center px-6 py-3">
|
||||
<div className="flex items-center px-6 py-3 safe-area-bottom">
|
||||
<div className="flex items-center gap-2 flex-1 bg-secondary rounded-full px-4 py-2.5">
|
||||
{isFetching ? (
|
||||
<svg
|
||||
@@ -321,14 +343,12 @@ export function MobileSearchSheet({ open, onClose }: MobileSearchSheetProps) {
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{query.length > 0 && (
|
||||
<button
|
||||
onClick={() => setQuery('')}
|
||||
className="size-5 shrink-0 flex items-center justify-center rounded-full bg-muted text-muted-foreground hover:bg-muted/80 transition-colors"
|
||||
>
|
||||
<X strokeWidth={4} className="size-3" />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="size-5 shrink-0 flex items-center justify-center rounded-full bg-muted text-muted-foreground hover:bg-muted/80 transition-colors"
|
||||
>
|
||||
<X strokeWidth={4} className="size-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,9 +22,12 @@ import '@fontsource-variable/inter';
|
||||
// (class changes for builtin themes, style-content changes for custom themes).
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||
import { Keyboard } from '@capacitor/keyboard';
|
||||
import { getBackgroundThemeMode, getBackgroundHex } from '@/lib/colorUtils';
|
||||
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
// Hide the iOS keyboard accessory bar (prev/next/done toolbar above the keyboard)
|
||||
Keyboard.setAccessoryBarVisible({ isVisible: false }).catch(() => {});
|
||||
/**
|
||||
* Read --background from the computed style of <html>, convert the HSL
|
||||
* value to a hex color, and update the native status bar to match.
|
||||
|
||||
Reference in New Issue
Block a user