mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-11-20 04:54:05 +01:00
Bump versions (#1173)
* Bump versions * Bump NPM versions, update to Svelte 5 * try improve flaky test * bump single-file-cli, remove ublock origin workaround * bump base images * replace libssl3
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { mount } from "svelte";
|
||||
import { Behavior, registerBehavior } from "./index";
|
||||
import SearchAutoCompleteComponent from "../components/SearchAutoComplete.svelte";
|
||||
|
||||
@@ -12,7 +13,7 @@ class SearchAutocomplete extends Behavior {
|
||||
|
||||
const container = document.createElement("div");
|
||||
|
||||
new SearchAutoCompleteComponent({
|
||||
mount(SearchAutoCompleteComponent, {
|
||||
target: container,
|
||||
props: {
|
||||
name: "q",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Behavior, registerBehavior } from "./index";
|
||||
import TagAutoCompleteComponent from "../components/TagAutocomplete.svelte";
|
||||
import { mount } from "svelte";
|
||||
|
||||
class TagAutocomplete extends Behavior {
|
||||
constructor(element) {
|
||||
@@ -12,7 +13,7 @@ class TagAutocomplete extends Behavior {
|
||||
|
||||
const container = document.createElement("div");
|
||||
|
||||
new TagAutoCompleteComponent({
|
||||
mount(TagAutoCompleteComponent, {
|
||||
target: container,
|
||||
props: {
|
||||
id: input.id,
|
||||
|
||||
@@ -2,22 +2,24 @@
|
||||
import {SearchHistory} from "./SearchHistory";
|
||||
import {api} from "../api";
|
||||
import {cache} from "../cache";
|
||||
import {clampText, debounce, getCurrentWord, getCurrentWordBounds} from "../util";
|
||||
import {clampText, debounce, getCurrentWord, getCurrentWordBounds, preventDefault} from "../util";
|
||||
|
||||
const searchHistory = new SearchHistory()
|
||||
|
||||
export let name;
|
||||
export let placeholder;
|
||||
export let value;
|
||||
export let mode = '';
|
||||
export let search;
|
||||
export let linkTarget = '_blank';
|
||||
let {
|
||||
name,
|
||||
placeholder,
|
||||
value = $bindable(),
|
||||
mode = '',
|
||||
search,
|
||||
linkTarget = '_blank'
|
||||
} = $props();
|
||||
|
||||
let isFocus = false;
|
||||
let isOpen = false;
|
||||
let suggestions = []
|
||||
let selectedIndex = undefined;
|
||||
let input = null;
|
||||
let isFocus = $state(false);
|
||||
let isOpen = $state(false);
|
||||
let suggestions = $state([])
|
||||
let selectedIndex = $state(undefined);
|
||||
let input = $state(null);
|
||||
|
||||
// Track current search query after loading the page
|
||||
searchHistory.pushCurrent()
|
||||
@@ -201,7 +203,7 @@
|
||||
<div class="form-autocomplete-input form-input" class:is-focused={isFocus}>
|
||||
<input type="search" class="form-input" name="{name}" placeholder="{placeholder}" autocomplete="off" value="{value}"
|
||||
bind:this={input}
|
||||
on:input={handleInput} on:keydown={handleKeyDown} on:focus={handleFocus} on:blur={handleBlur}>
|
||||
oninput={handleInput} onkeydown={handleKeyDown} onfocus={handleFocus} onblur={handleBlur}>
|
||||
</div>
|
||||
|
||||
<ul class="menu" class:open={isOpen}>
|
||||
@@ -210,7 +212,7 @@
|
||||
{/if}
|
||||
{#each suggestions.tags as suggestion}
|
||||
<li class="menu-item" class:selected={selectedIndex === suggestion.index}>
|
||||
<a href="#" on:mousedown|preventDefault={() => completeSuggestion(suggestion)}>
|
||||
<a href="#" onmousedown={preventDefault(() => completeSuggestion(suggestion))}>
|
||||
{suggestion.label}
|
||||
</a>
|
||||
</li>
|
||||
@@ -221,7 +223,7 @@
|
||||
{/if}
|
||||
{#each suggestions.recentSearches as suggestion}
|
||||
<li class="menu-item" class:selected={selectedIndex === suggestion.index}>
|
||||
<a href="#" on:mousedown|preventDefault={() => completeSuggestion(suggestion)}>
|
||||
<a href="#" onmousedown={preventDefault(() => completeSuggestion(suggestion))}>
|
||||
{suggestion.label}
|
||||
</a>
|
||||
</li>
|
||||
@@ -232,7 +234,7 @@
|
||||
{/if}
|
||||
{#each suggestions.bookmarks as suggestion}
|
||||
<li class="menu-item" class:selected={selectedIndex === suggestion.index}>
|
||||
<a href="#" on:mousedown|preventDefault={() => completeSuggestion(suggestion)}>
|
||||
<a href="#" onmousedown={preventDefault(() => completeSuggestion(suggestion))}>
|
||||
{suggestion.label}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
<script>
|
||||
import {cache} from "../cache";
|
||||
import {getCurrentWord, getCurrentWordBounds} from "../util";
|
||||
import {getCurrentWord, getCurrentWordBounds, preventDefault} from "../util";
|
||||
|
||||
export let id;
|
||||
export let name;
|
||||
export let value;
|
||||
export let placeholder;
|
||||
export let ariaDescribedBy;
|
||||
export let variant = 'default';
|
||||
let {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
placeholder,
|
||||
ariaDescribedBy,
|
||||
variant = 'default'
|
||||
} = $props();
|
||||
|
||||
let isFocus = false;
|
||||
let isOpen = false;
|
||||
let isFocus = $state(false);
|
||||
let isOpen = $state(false);
|
||||
let input = null;
|
||||
let suggestionList = null;
|
||||
let suggestionList = $state(null);
|
||||
|
||||
let suggestions = [];
|
||||
let selectedIndex = 0;
|
||||
let suggestions = $state([]);
|
||||
let selectedIndex = $state(0);
|
||||
|
||||
function handleFocus() {
|
||||
isFocus = true;
|
||||
@@ -112,8 +114,8 @@
|
||||
<input id="{id}" name="{name}" value="{value ||''}" placeholder="{placeholder || ' '}"
|
||||
class="form-input" type="text" autocomplete="off" autocapitalize="off"
|
||||
aria-describedby="{ariaDescribedBy}"
|
||||
on:input={handleInput} on:keydown={handleKeyDown}
|
||||
on:focus={handleFocus} on:blur={handleBlur}>
|
||||
oninput={handleInput} onkeydown={handleKeyDown}
|
||||
onfocus={handleFocus} onblur={handleBlur}>
|
||||
</div>
|
||||
|
||||
<!-- autocomplete suggestion list -->
|
||||
@@ -122,7 +124,7 @@
|
||||
<!-- menu list items -->
|
||||
{#each suggestions as tag,i}
|
||||
<li class="menu-item" class:selected={selectedIndex === i}>
|
||||
<a href="#" on:mousedown|preventDefault={() => complete(tag)}>
|
||||
<a href="#" onmousedown={preventDefault(() => complete(tag))}>
|
||||
{tag.name}
|
||||
</a>
|
||||
</li>
|
||||
@@ -141,14 +143,14 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-autocomplete-input {
|
||||
.form-autocomplete .form-autocomplete-input {
|
||||
box-sizing: border-box;
|
||||
height: var(--control-size);
|
||||
min-height: var(--control-size);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.form-autocomplete-input input {
|
||||
.form-autocomplete .form-autocomplete-input input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
|
||||
@@ -9,6 +9,13 @@ export function debounce(callback, delay = 250) {
|
||||
};
|
||||
}
|
||||
|
||||
export function preventDefault(fn) {
|
||||
return function (event) {
|
||||
event.preventDefault();
|
||||
fn.call(this, event);
|
||||
};
|
||||
}
|
||||
|
||||
export function clampText(text, maxChars = 30) {
|
||||
if (!text || text.length <= 30) return text;
|
||||
|
||||
|
||||
@@ -39,9 +39,10 @@ def create_snapshot(asset: BookmarkAsset):
|
||||
# Store as gzip in asset folder
|
||||
filename = _generate_asset_filename(asset, asset.bookmark.url, "html.gz")
|
||||
filepath = os.path.join(settings.LD_ASSET_FOLDER, filename)
|
||||
with open(temp_filepath, "rb") as temp_file, gzip.open(
|
||||
filepath, "wb"
|
||||
) as gz_file:
|
||||
with (
|
||||
open(temp_filepath, "rb") as temp_file,
|
||||
gzip.open(filepath, "wb") as gz_file,
|
||||
):
|
||||
shutil.copyfileobj(temp_file, gz_file)
|
||||
|
||||
# Remove temporary file
|
||||
|
||||
@@ -22,9 +22,10 @@ def create_snapshot(url: str, filepath: str):
|
||||
command = f"{monolith_path} '{url}' {monolith_options} -o {temp_filepath}"
|
||||
subprocess.run(command, check=True, shell=True)
|
||||
|
||||
with open(temp_filepath, "rb") as raw_file, gzip.open(
|
||||
filepath, "wb"
|
||||
) as gz_file:
|
||||
with (
|
||||
open(temp_filepath, "rb") as raw_file,
|
||||
gzip.open(filepath, "wb") as gz_file,
|
||||
):
|
||||
shutil.copyfileobj(raw_file, gz_file)
|
||||
|
||||
os.remove(temp_filepath)
|
||||
|
||||
@@ -365,7 +365,8 @@ li[ld-bookmark-item] {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: calc(
|
||||
-1 * calc(var(--bulk-edit-toggle-width) + var(--bulk-edit-toggle-offset))
|
||||
-1 *
|
||||
calc(var(--bulk-edit-toggle-width) + var(--bulk-edit-toggle-offset))
|
||||
);
|
||||
width: calc(
|
||||
var(--bulk-edit-toggle-width) + var(--bulk-edit-toggle-offset)
|
||||
|
||||
@@ -49,20 +49,22 @@
|
||||
--body-color-contrast: var(--gray-100);
|
||||
|
||||
/* Fonts */
|
||||
--base-font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI",
|
||||
Roboto;
|
||||
--mono-font-family: "SF Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Courier,
|
||||
monospace;
|
||||
--base-font-family:
|
||||
-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto;
|
||||
--mono-font-family:
|
||||
"SF Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Courier, monospace;
|
||||
--fallback-font-family: "Helvetica Neue", sans-serif;
|
||||
--cjk-zh-hans-font-family: var(--base-font-family), "PingFang SC",
|
||||
"Hiragino Sans GB", "Microsoft YaHei", var(--fallback-font-family);
|
||||
--cjk-zh-hant-font-family: var(--base-font-family), "PingFang TC",
|
||||
"Hiragino Sans CNS", "Microsoft JhengHei", var(--fallback-font-family);
|
||||
--cjk-jp-font-family: var(--base-font-family), "Hiragino Sans",
|
||||
"Hiragino Kaku Gothic Pro", "Yu Gothic", YuGothic, Meiryo,
|
||||
var(--fallback-font-family);
|
||||
--cjk-ko-font-family: var(--base-font-family), "Malgun Gothic",
|
||||
var(--fallback-font-family);
|
||||
--cjk-zh-hans-font-family:
|
||||
var(--base-font-family), "PingFang SC", "Hiragino Sans GB",
|
||||
"Microsoft YaHei", var(--fallback-font-family);
|
||||
--cjk-zh-hant-font-family:
|
||||
var(--base-font-family), "PingFang TC", "Hiragino Sans CNS",
|
||||
"Microsoft JhengHei", var(--fallback-font-family);
|
||||
--cjk-jp-font-family:
|
||||
var(--base-font-family), "Hiragino Sans", "Hiragino Kaku Gothic Pro",
|
||||
"Yu Gothic", YuGothic, Meiryo, var(--fallback-font-family);
|
||||
--cjk-ko-font-family:
|
||||
var(--base-font-family), "Malgun Gothic", var(--fallback-font-family);
|
||||
--body-font-family: var(--base-font-family), var(--fallback-font-family);
|
||||
|
||||
/* Unit sizes */
|
||||
@@ -145,6 +147,6 @@
|
||||
/* Shadows */
|
||||
--box-shadow-xs: rgba(0, 0, 0, 0.05) 0px 1px 2px 0px;
|
||||
--box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
--box-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1),
|
||||
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--box-shadow-lg:
|
||||
0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class A11yNavigationFocusTest(LinkdingE2ETestCase):
|
||||
focused_tag = page.evaluate(
|
||||
"document.activeElement?.tagName + '|' + document.activeElement?.name"
|
||||
)
|
||||
page.wait_for_timeout(timeout=1000)
|
||||
self.assertEqual("INPUT|url", focused_tag)
|
||||
|
||||
def test_page_navigation_focus(self):
|
||||
|
||||
Reference in New Issue
Block a user