Adds a quick "Search on Goodreads" action so readers can jump straight to Goodreads to track a book instead of retyping the title there. - Library: a Goodreads button in the Book Details view (works on web, desktop and mobile) searching the book's title + author, plus a "Search on Goodreads" item in the desktop right-click context menu. - Reader: Goodreads is added as a built-in web-search provider so highlighted text (e.g. a short-story title inside a magazine) can be looked up on Goodreads. Disabled by default like the other built-ins; enable it in Settings -> Dictionaries. Both surfaces are used because the native context menu is desktop-only; the Book Details button covers web and mobile. Adds a shared openExternalUrl() helper and translates "Search on Goodreads" across all locales (the Goodreads brand name is kept verbatim). Closes #4543 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import { Book } from '@/types/book';
|
||||
|
||||
const GOODREADS_SEARCH_URL = 'https://www.goodreads.com/search';
|
||||
|
||||
/** Build a Goodreads search URL for an arbitrary query string. */
|
||||
export const getGoodreadsSearchUrl = (query: string): string =>
|
||||
`${GOODREADS_SEARCH_URL}?q=${encodeURIComponent(query.trim())}`;
|
||||
|
||||
/**
|
||||
* Compose the Goodreads search query for a book from its title and author.
|
||||
* The author improves match precision; it's dropped when empty.
|
||||
*/
|
||||
export const getBookGoodreadsQuery = (book: Pick<Book, 'title' | 'author'>): string =>
|
||||
[book.title, book.author]
|
||||
.map((part) => part?.trim())
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
@@ -1,6 +1,20 @@
|
||||
import { openUrl } from '@tauri-apps/plugin-opener';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
|
||||
/**
|
||||
* Open an external URL in the system browser. On Tauri the in-app webview
|
||||
* ignores `target="_blank"`, so route through the opener plugin; on web fall
|
||||
* back to `window.open`. Unlike `interceptWindowOpen`, this works without the
|
||||
* reader-scoped `window.open` override being installed.
|
||||
*/
|
||||
export const openExternalUrl = (url: string) => {
|
||||
if (isTauriAppPlatform()) {
|
||||
void openUrl(url).catch((err) => console.warn('Failed to open external URL', url, err));
|
||||
} else {
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
};
|
||||
|
||||
export const interceptWindowOpen = () => {
|
||||
const windowOpen = window.open;
|
||||
globalThis.open = function (
|
||||
|
||||
Reference in New Issue
Block a user