diff --git a/package.json b/package.json index c5d07e99..9af8a483 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "pym.js": "^1.3.2", "svelte-fa": "^2.4.0", "svelte-intersection-observer": "^0.10.0", + "svelte-search": "^2.0.1", "ua-parser-js": "^0.7.27" }, "exports": { @@ -211,4 +212,4 @@ ".": "./dist/index.js" }, "svelte": "./dist/index.js" -} \ No newline at end of file +} diff --git a/src/components/Framer/Framer.svelte b/src/components/Framer/Framer.svelte index f12658ac..945b984f 100644 --- a/src/components/Framer/Framer.svelte +++ b/src/components/Framer/Framer.svelte @@ -7,6 +7,7 @@ import Resizer from './Resizer/index.svelte'; import { width } from './stores.js'; import getUniqNames from './uniqNames.js'; + import Typeahead from './Typeahead/index.svelte'; export let embeds; export let breakpoints = [330, 510, 660, 930, 1200]; @@ -46,22 +47,33 @@ /> - + Live link + + + + +
+

Preview

+
@@ -90,29 +102,21 @@ margin: 20px 0; } - nav { - text-align: center; - margin: 0 auto 20px; - max-width: 900px; - button { - margin: 0 4px 5px; - background-color: transparent; - border: 0; - color: #999; - padding: 2px 2px; - cursor: pointer; - @include font-display; - font-weight: 400; - &.active { - border-bottom: 2px solid #666; - color: #666; - } - &:focus { - outline: none; - } + div#typeahead-container { + max-width: 660px; + margin: 0 auto 15px; + position: relative; + div.embed-link { + position: absolute; + top: 0; + right: 0; + display: inline-block; + z-index: 2; a { + @include font-display; color: #bbb; font-size: 12px; + text-decoration: none !important; &:hover { 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 { border: 1px solid #ddd; margin: 0 auto; diff --git a/src/components/Framer/Typeahead/fuzzy.js b/src/components/Framer/Typeahead/fuzzy.js new file mode 100644 index 00000000..9d998b57 --- /dev/null +++ b/src/components/Framer/Typeahead/fuzzy.js @@ -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: '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: '' +// +// // string to put after matching character +// , post: '' +// +// // 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; diff --git a/src/components/Framer/Typeahead/index.svelte b/src/components/Framer/Typeahead/index.svelte new file mode 100644 index 00000000..e0b36c38 --- /dev/null +++ b/src/components/Framer/Typeahead/index.svelte @@ -0,0 +1,349 @@ + + + + +
+ +
    + {#if showResults} + {#each results as result, index} +
  • + + {@html result.string} + +
  • + {/each} + {/if} + {#if $$slots['no-results'] && !hideDropdown && value.length > 0 && results.length === 0} +
    + +
    + {/if} +
+
+ + diff --git a/yarn.lock b/yarn.lock index 3f25f5ee..44bbb63a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11279,6 +11279,11 @@ svelte-preprocess@^4.10.7: sorcery "^0.10.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: version "0.5.13" resolved "https://registry.yarnpkg.com/svelte2tsx/-/svelte2tsx-0.5.13.tgz#5c36a6510d7121e38afbe0d8ec4610992c39ad87"