closes #25
This commit is contained in:
parent
1c2dfbb08d
commit
9898d9e6d7
5 changed files with 537 additions and 35 deletions
|
|
@ -89,6 +89,7 @@
|
||||||
"pym.js": "^1.3.2",
|
"pym.js": "^1.3.2",
|
||||||
"svelte-fa": "^2.4.0",
|
"svelte-fa": "^2.4.0",
|
||||||
"svelte-intersection-observer": "^0.10.0",
|
"svelte-intersection-observer": "^0.10.0",
|
||||||
|
"svelte-search": "^2.0.1",
|
||||||
"ua-parser-js": "^0.7.27"
|
"ua-parser-js": "^0.7.27"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
import Resizer from './Resizer/index.svelte';
|
import Resizer from './Resizer/index.svelte';
|
||||||
import { width } from './stores.js';
|
import { width } from './stores.js';
|
||||||
import getUniqNames from './uniqNames.js';
|
import getUniqNames from './uniqNames.js';
|
||||||
|
import Typeahead from './Typeahead/index.svelte';
|
||||||
|
|
||||||
export let embeds;
|
export let embeds;
|
||||||
export let breakpoints = [330, 510, 660, 930, 1200];
|
export let breakpoints = [330, 510, 660, 930, 1200];
|
||||||
|
|
@ -46,22 +47,33 @@
|
||||||
/>
|
/>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<nav>
|
<div id="typeahead-container">
|
||||||
{#each embeds as embed, i}
|
<div class="embed-link">
|
||||||
<button
|
<a
|
||||||
on:click="{() => {
|
rel="external"
|
||||||
activeEmbed = embed;
|
target="_blank"
|
||||||
}}"
|
href="{activeEmbed}"
|
||||||
class:active="{activeEmbed === embed}"
|
title="{activeEmbed}"
|
||||||
>
|
>
|
||||||
{embedTitles[i]}
|
Live link <Fa icon="{faLink}" />
|
||||||
<a rel="external" target="_blank" href="{embed}" title="{embed}">
|
</a>
|
||||||
<Fa icon="{faLink}" />
|
</div>
|
||||||
</a>
|
<Typeahead
|
||||||
</button>
|
label="Select an embed"
|
||||||
{/each}
|
value="{embedTitles[0]}"
|
||||||
</nav>
|
extract="{(d) => embedTitles[d.index]}"
|
||||||
|
data="{embeds.map((embed, index) => ({ index, embed }))}"
|
||||||
|
placeholder="{'Search'}"
|
||||||
|
showDropdownOnFocus="{true}"
|
||||||
|
on:select="{({ detail }) => {
|
||||||
|
activeEmbed = detail.original.embed;
|
||||||
|
}}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="preview-label" style="width:{$width}px;">
|
||||||
|
<p>Preview</p>
|
||||||
|
</div>
|
||||||
<div id="frame-parent" style="width:{$width}px;"></div>
|
<div id="frame-parent" style="width:{$width}px;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -90,29 +102,21 @@
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
div#typeahead-container {
|
||||||
text-align: center;
|
max-width: 660px;
|
||||||
margin: 0 auto 20px;
|
margin: 0 auto 15px;
|
||||||
max-width: 900px;
|
position: relative;
|
||||||
button {
|
div.embed-link {
|
||||||
margin: 0 4px 5px;
|
position: absolute;
|
||||||
background-color: transparent;
|
top: 0;
|
||||||
border: 0;
|
right: 0;
|
||||||
color: #999;
|
display: inline-block;
|
||||||
padding: 2px 2px;
|
z-index: 2;
|
||||||
cursor: pointer;
|
|
||||||
@include font-display;
|
|
||||||
font-weight: 400;
|
|
||||||
&.active {
|
|
||||||
border-bottom: 2px solid #666;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
a {
|
a {
|
||||||
|
@include font-display;
|
||||||
color: #bbb;
|
color: #bbb;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
text-decoration: none !important;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +124,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div#preview-label {
|
||||||
|
margin: 0 auto;
|
||||||
|
p {
|
||||||
|
@include font-display;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin: 0 0 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#frame-parent {
|
#frame-parent {
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
|
||||||
133
src/components/Framer/Typeahead/fuzzy.js
Normal file
133
src/components/Framer/Typeahead/fuzzy.js
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* Fuzzy
|
||||||
|
* https://github.com/myork/fuzzy
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Matt York
|
||||||
|
* Licensed under the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fuzzy = {};
|
||||||
|
|
||||||
|
// Return all elements of `array` that have a fuzzy
|
||||||
|
// match against `pattern`.
|
||||||
|
fuzzy.simpleFilter = function (pattern, array) {
|
||||||
|
return array.filter(function (str) {
|
||||||
|
return fuzzy.test(pattern, str);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Does `pattern` fuzzy match `str`?
|
||||||
|
fuzzy.test = function (pattern, str) {
|
||||||
|
return fuzzy.match(pattern, str) !== null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If `pattern` matches `str`, wrap each matching character
|
||||||
|
// in `opts.pre` and `opts.post`. If no match, return null
|
||||||
|
fuzzy.match = function (pattern, str, opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
let patternIdx = 0;
|
||||||
|
const result = [];
|
||||||
|
const len = str.length;
|
||||||
|
let totalScore = 0;
|
||||||
|
let currScore = 0;
|
||||||
|
// prefix
|
||||||
|
const pre = opts.pre || '';
|
||||||
|
// suffix
|
||||||
|
const post = opts.post || '';
|
||||||
|
// String to compare against. This might be a lowercase version of the
|
||||||
|
// raw string
|
||||||
|
const compareString = (opts.caseSensitive && str) || str.toLowerCase();
|
||||||
|
let ch;
|
||||||
|
|
||||||
|
pattern = (opts.caseSensitive && pattern) || pattern.toLowerCase();
|
||||||
|
|
||||||
|
// For each character in the string, either add it to the result
|
||||||
|
// or wrap in template if it's the next string in the pattern
|
||||||
|
for (let idx = 0; idx < len; idx++) {
|
||||||
|
ch = str[idx];
|
||||||
|
if (compareString[idx] === pattern[patternIdx]) {
|
||||||
|
ch = pre + ch + post;
|
||||||
|
patternIdx += 1;
|
||||||
|
|
||||||
|
// consecutive characters should increase the score more than linearly
|
||||||
|
currScore += 1 + currScore;
|
||||||
|
} else {
|
||||||
|
currScore = 0;
|
||||||
|
}
|
||||||
|
totalScore += currScore;
|
||||||
|
result[result.length] = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return rendered string if we have a match for every char
|
||||||
|
if (patternIdx === pattern.length) {
|
||||||
|
// if the string is an exact match with pattern, totalScore should be maxed
|
||||||
|
totalScore = compareString === pattern ? Infinity : totalScore;
|
||||||
|
return { rendered: result.join(''), score: totalScore };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The normal entry point. Filters `arr` for matches against `pattern`.
|
||||||
|
// It returns an array with matching values of the type:
|
||||||
|
//
|
||||||
|
// [{
|
||||||
|
// string: '<b>lah' // The rendered string
|
||||||
|
// , index: 2 // The index of the element in `arr`
|
||||||
|
// , original: 'blah' // The original element in `arr`
|
||||||
|
// }]
|
||||||
|
//
|
||||||
|
// `opts` is an optional argument bag. Details:
|
||||||
|
//
|
||||||
|
// opts = {
|
||||||
|
// // string to put before a matching character
|
||||||
|
// pre: '<b>'
|
||||||
|
//
|
||||||
|
// // string to put after matching character
|
||||||
|
// , post: '</b>'
|
||||||
|
//
|
||||||
|
// // Optional function. Input is an entry in the given arr`,
|
||||||
|
// // output should be the string to test `pattern` against.
|
||||||
|
// // In this example, if `arr = [{crying: 'koala'}]` we would return
|
||||||
|
// // 'koala'.
|
||||||
|
// , extract: function(arg) { return arg.crying; }
|
||||||
|
// }
|
||||||
|
fuzzy.filter = function (pattern, arr, opts) {
|
||||||
|
if (!arr || arr.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (typeof pattern !== 'string') {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
opts = opts || {};
|
||||||
|
return (
|
||||||
|
arr
|
||||||
|
.reduce(function (prev, element, idx, arr) {
|
||||||
|
let str = element;
|
||||||
|
if (opts.extract) {
|
||||||
|
str = opts.extract(element);
|
||||||
|
}
|
||||||
|
const rendered = fuzzy.match(pattern, str, opts);
|
||||||
|
if (rendered != null) {
|
||||||
|
prev[prev.length] = {
|
||||||
|
string: rendered.rendered,
|
||||||
|
score: rendered.score,
|
||||||
|
index: idx,
|
||||||
|
original: element,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Sort by score. Browsers are inconsistent wrt stable/unstable
|
||||||
|
// sorting, so force stable by using the index in the case of tie.
|
||||||
|
// See http://ofb.net/~sethml/is-sort-stable.html
|
||||||
|
.sort(function (a, b) {
|
||||||
|
const compare = b.score - a.score;
|
||||||
|
if (compare) return compare;
|
||||||
|
return a.index - b.index;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default fuzzy;
|
||||||
349
src/components/Framer/Typeahead/index.svelte
Normal file
349
src/components/Framer/Typeahead/index.svelte
Normal file
|
|
@ -0,0 +1,349 @@
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* @typedef {Object} TItem
|
||||||
|
* @property {number} index
|
||||||
|
* @property {string} embed
|
||||||
|
*/
|
||||||
|
|
||||||
|
export let id = 'typeahead-' + Math.random().toString(36);
|
||||||
|
export let value = '';
|
||||||
|
|
||||||
|
/** @type {TItem[]} */
|
||||||
|
export let data = [];
|
||||||
|
|
||||||
|
/** @type {(item: TItem) => any} */
|
||||||
|
export let extract = (item) => item;
|
||||||
|
|
||||||
|
/** @type {(item: TItem) => boolean} */
|
||||||
|
export let disable = (item) => false;
|
||||||
|
|
||||||
|
/** @type {(item: TItem) => boolean} */
|
||||||
|
export let filter = (item) => false;
|
||||||
|
|
||||||
|
/** Set to `false` to prevent the first result from being selected */
|
||||||
|
export let autoselect = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to `keep` to keep the search field unchanged after select, set to `clear` to auto-clear search field
|
||||||
|
* @type {"update" | "clear" | "keep"}
|
||||||
|
*/
|
||||||
|
export let inputAfterSelect = 'update';
|
||||||
|
|
||||||
|
/** @type {{ original: TItem; index: number; score: number; string: string; disabled?: boolean; }[]} */
|
||||||
|
export let results = [];
|
||||||
|
|
||||||
|
/** Set to `true` to re-focus the input after selecting a result */
|
||||||
|
export let focusAfterSelect = false;
|
||||||
|
|
||||||
|
/** Set to `true` to only show results when the input is focused */
|
||||||
|
export let showDropdownOnFocus = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the maximum number of results to return
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
export let limit = Infinity;
|
||||||
|
|
||||||
|
import fuzzy from './fuzzy.js';
|
||||||
|
import Search from 'svelte-search';
|
||||||
|
import { tick, createEventDispatcher, afterUpdate } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
let comboboxRef = null;
|
||||||
|
let searchRef = null;
|
||||||
|
let hideDropdown = false;
|
||||||
|
let selectedIndex = -1;
|
||||||
|
let prevResults = '';
|
||||||
|
let isFocused = false;
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
if (prevResults !== resultsId && autoselect) {
|
||||||
|
selectedIndex = getNextNonDisabledIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevResults !== resultsId && !$$slots['no-results']) {
|
||||||
|
hideDropdown = results.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevResults = resultsId;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function select() {
|
||||||
|
const result = results[selectedIndex];
|
||||||
|
|
||||||
|
if (result.disabled) return;
|
||||||
|
|
||||||
|
const selectedValue = extract(result.original);
|
||||||
|
const searchedValue = value;
|
||||||
|
|
||||||
|
if (inputAfterSelect === 'clear') value = '';
|
||||||
|
if (inputAfterSelect === 'update') value = selectedValue;
|
||||||
|
|
||||||
|
dispatch('select', {
|
||||||
|
selectedIndex,
|
||||||
|
searched: searchedValue,
|
||||||
|
selected: selectedValue,
|
||||||
|
original: result.original,
|
||||||
|
originalIndex: result.index,
|
||||||
|
});
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
if (focusAfterSelect) searchRef.focus();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {() => number} */
|
||||||
|
function getNextNonDisabledIndex() {
|
||||||
|
let index = 0;
|
||||||
|
let disabled = results[index]?.disabled ?? false;
|
||||||
|
|
||||||
|
while (disabled) {
|
||||||
|
if (index === results.length) {
|
||||||
|
index = 0;
|
||||||
|
} else {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled = results[index]?.disabled ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {(direction: -1 | 1) => void} */
|
||||||
|
function change(direction) {
|
||||||
|
let index =
|
||||||
|
direction === 1 && selectedIndex === results.length - 1
|
||||||
|
? 0
|
||||||
|
: selectedIndex + direction;
|
||||||
|
if (index < 0) index = results.length - 1;
|
||||||
|
|
||||||
|
let disabled = results[index].disabled;
|
||||||
|
|
||||||
|
while (disabled) {
|
||||||
|
if (index === results.length) {
|
||||||
|
index = 0;
|
||||||
|
} else {
|
||||||
|
index += direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled = results[index].disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = () => (hideDropdown = false);
|
||||||
|
const close = () => (hideDropdown = true);
|
||||||
|
|
||||||
|
$: options = { pre: '<mark>', post: '</mark>', extract };
|
||||||
|
$: results =
|
||||||
|
value !== ''
|
||||||
|
? fuzzy
|
||||||
|
.filter(value, data, options)
|
||||||
|
.filter(({ score }) => score > 0)
|
||||||
|
.slice(0, limit)
|
||||||
|
.filter((result) => !filter(result.original))
|
||||||
|
.map((result) => ({ ...result, disabled: disable(result.original) }))
|
||||||
|
: data.slice(0, 10).map((d) => ({ string: extract(d), original: d }));
|
||||||
|
|
||||||
|
$: resultsId = results.map((result) => extract(result.original)).join('');
|
||||||
|
$: showResults = !hideDropdown && results.length > 0 && isFocused;
|
||||||
|
$: if (showDropdownOnFocus) {
|
||||||
|
showResults = showResults && isFocused;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window
|
||||||
|
on:click="{({ target }) => {
|
||||||
|
if (!hideDropdown && !comboboxRef?.contains(target)) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
data-svelte-typeahead
|
||||||
|
bind:this="{comboboxRef}"
|
||||||
|
role="combobox"
|
||||||
|
aria-haspopup="listbox"
|
||||||
|
aria-owns="{id}-listbox"
|
||||||
|
class:dropdown="{results.length > 0}"
|
||||||
|
aria-expanded="{showResults}"
|
||||||
|
id="{id}-typeahead"
|
||||||
|
>
|
||||||
|
<Search
|
||||||
|
id="{id}"
|
||||||
|
removeFormAriaAttributes="{true}"
|
||||||
|
{...$$restProps}
|
||||||
|
bind:ref="{searchRef}"
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="{id}-listbox"
|
||||||
|
aria-labelledby="{id}-label"
|
||||||
|
aria-activedescendant="{selectedIndex >= 0 &&
|
||||||
|
!hideDropdown &&
|
||||||
|
results.length > 0
|
||||||
|
? `${id}-result-${selectedIndex}`
|
||||||
|
: null}"
|
||||||
|
bind:value
|
||||||
|
on:type
|
||||||
|
on:input
|
||||||
|
on:change
|
||||||
|
on:focus
|
||||||
|
on:focus="{() => {
|
||||||
|
open();
|
||||||
|
if (showDropdownOnFocus) {
|
||||||
|
showResults = true;
|
||||||
|
isFocused = true;
|
||||||
|
}
|
||||||
|
}}"
|
||||||
|
on:clear
|
||||||
|
on:clear="{open}"
|
||||||
|
on:blur
|
||||||
|
on:keydown
|
||||||
|
on:keydown="{(e) => {
|
||||||
|
if (results.length === 0) return;
|
||||||
|
|
||||||
|
switch (e.key) {
|
||||||
|
case 'Enter':
|
||||||
|
select();
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
e.preventDefault();
|
||||||
|
change(1);
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
e.preventDefault();
|
||||||
|
change(-1);
|
||||||
|
break;
|
||||||
|
case 'Escape':
|
||||||
|
e.preventDefault();
|
||||||
|
value = '';
|
||||||
|
searchRef?.focus();
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}}"
|
||||||
|
/>
|
||||||
|
<ul
|
||||||
|
class:svelte-typeahead-list="{true}"
|
||||||
|
role="listbox"
|
||||||
|
aria-labelledby="{id}-label"
|
||||||
|
id="{id}-listbox"
|
||||||
|
>
|
||||||
|
{#if showResults}
|
||||||
|
{#each results as result, index}
|
||||||
|
<li
|
||||||
|
role="option"
|
||||||
|
id="{id}-result-{index}"
|
||||||
|
class:selected="{selectedIndex === index}"
|
||||||
|
class:disabled="{result.disabled}"
|
||||||
|
aria-selected="{selectedIndex === index}"
|
||||||
|
on:click="{() => {
|
||||||
|
if (result.disabled) return;
|
||||||
|
selectedIndex = index;
|
||||||
|
select();
|
||||||
|
}}"
|
||||||
|
on:mouseenter="{() => {
|
||||||
|
if (result.disabled) return;
|
||||||
|
selectedIndex = index;
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
<slot result="{result}" index="{index}" value="{value}">
|
||||||
|
{@html result.string}
|
||||||
|
</slot>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{#if $$slots['no-results'] && !hideDropdown && value.length > 0 && results.length === 0}
|
||||||
|
<div class:no-results="{true}">
|
||||||
|
<slot name="no-results" value="{value}" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../../scss/fonts/mixins';
|
||||||
|
|
||||||
|
[data-svelte-typeahead] {
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
[aria-expanded='true'] ul {
|
||||||
|
z-index: 1;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
// box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
li,
|
||||||
|
.no-results {
|
||||||
|
padding: 0.25rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
cursor: pointer;
|
||||||
|
:global(mark) {
|
||||||
|
padding: 0;
|
||||||
|
background-color: #ffff9a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:not(:last-of-type) {
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:hover {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected:hover {
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global([data-svelte-search] label) {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #aaa;
|
||||||
|
@include font-display;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global([data-svelte-search] input) {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
background: none;
|
||||||
|
font-size: 1rem;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
@include font-sans;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global([data-svelte-search] input:focus) {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -11279,6 +11279,11 @@ svelte-preprocess@^4.10.7:
|
||||||
sorcery "^0.10.0"
|
sorcery "^0.10.0"
|
||||||
strip-indent "^3.0.0"
|
strip-indent "^3.0.0"
|
||||||
|
|
||||||
|
svelte-search@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-search/-/svelte-search-2.0.1.tgz#d8b5ef9ac152f045a5c74a1b75c9d51c0091c839"
|
||||||
|
integrity sha512-JBoObru/BUk86EmuRtYBa99xnH1RB8jqDuYYJHH0PUzN9BINo1+1GZataC/m5368BG3kZRb3wZI5ztjoi1WWXg==
|
||||||
|
|
||||||
svelte2tsx@^0.5.13:
|
svelte2tsx@^0.5.13:
|
||||||
version "0.5.13"
|
version "0.5.13"
|
||||||
resolved "https://registry.yarnpkg.com/svelte2tsx/-/svelte2tsx-0.5.13.tgz#5c36a6510d7121e38afbe0d8ec4610992c39ad87"
|
resolved "https://registry.yarnpkg.com/svelte2tsx/-/svelte2tsx-0.5.13.tgz#5c36a6510d7121e38afbe0d8ec4610992c39ad87"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue