Browse Source

refactor, v0.1.0

- use dexie instead of idb_wrapper.imba
- use dexie-export-import instead of upload.imba
- use downloadjs instead of download.imba
- use fzi instead of bundling fzy.imba
- rename link.link to link.url in database v2
- change default links
- use config.search_engine object for search engine options
- allow multiple of same name
- show date in main-input instead of fuzzyhome version
- print fuzzyhome version in console
main
familyfriendlymikey 2 years ago
parent
commit
3a2fb9f9bf
  1. 490
      app/client.imba
  2. 5
      app/state.imba
  3. 14
      app/utils/download.imba
  4. 95
      app/utils/fzy.imba
  5. 94
      app/utils/idb_wrapper.imba
  6. 14
      app/utils/upload.imba
  7. 2674
      package-lock.json
  8. 11
      package.json
  9. 2
      sw.imba

490
app/client.imba

@ -1,98 +1,129 @@
let p = console.log let p = console.log
import { sortBy } from 'lodash'
import { version } from '../package.json' import { version } from '../package.json'
import fzy from './utils/fzy' import { orderBy } from 'lodash'
import download_json_file from './utils/download' import Dexie from 'dexie'
import upload_json_file from './utils/upload' import fzi from 'fzi'
import idb_wrapper from './utils/idb_wrapper' import download from 'downloadjs'
import state from './state' import 'dexie-export-import'
import 'dexie-observable'
let state = {
query: ''
links: []
scored_links: []
}
let db = new idb_wrapper 'fuzzyhome', 'links', 1 let config = {
db.open! search_engine: {}
}
global css body let db = new Dexie 'fuzzyhome'
d:flex fld:column jc:flex-start ai:center db.version(1).stores({
m:0 w:100% h:100% bg:#20222f links: "++id,name,link"
ff:sans-serif fw:1 })
db.version(2).stores({
links: "$$id,name,url"
}).upgrade(do |trans|
trans.links.toCollection!.modify(do |link|
link.url = link.link
delete link.link
delete link.last_opened
)
)
global._fuzzyhome_delete_everything = do
return unless window.confirm "This will delete everything. Are you sure?"
indexedDB.deleteDatabase("fuzzyhome")
delete localStorage.fuzzyhome_config
delete localStorage.fuzzyhome_visited
p "fuzzyhome version {version}"
tag app tag app
selection_index = 0 selection_index = 0
settings_active = no settings_active = no
loading_add = no
fatal_error = no
get render? do mounted? get render? do mounted?
def mount def mount
try
await reload_db!
catch e
err "loading database", e
fatal_error = yes
return
unless global.localStorage.fuzzyhome_visited unless global.localStorage.fuzzyhome_visited
await put_link { name: "fuzzy home help", link: "github.com/familyfriendlymikey/fuzzyhome" } await add_link { name: "help", url: "github.com/familyfriendlymikey/fuzzyhome" }
await put_link { name: "google", link: "google.com" } await add_link { name: "google", url: "google.com" }
await put_link { name: "youtube", link: "youtube.com" } await add_link { name: "youtube", url: "youtube.com" }
await add_link { name: "3000", url: "localhost:3000" }
global.localStorage.fuzzyhome_visited = yes global.localStorage.fuzzyhome_visited = yes
if not global.localStorage.fuzzyhome_config if not global.localStorage.fuzzyhome_config
let search_engine_url = 'www.google.com/search?q=' let url = 'www.google.com/search?q='
let search_engine_hostname = 'www.google.com' let hostname = 'www.google.com'
let search_engine_frequency = 0 let frequency = 0
let search_engine_icon = await fetch_image_as_base_64 'google.com' let icon = await fetch_image_as_base_64 'google.com'
state.config = { config.search_engine = { url, hostname, icon, frequency }
search_engine_url
search_engine_hostname
search_engine_icon
search_engine_frequency
}
save_config! save_config!
else else
load_config! load_config!
state.links = await db.reload! def save_config
sort_links! global.localStorage.fuzzyhome_config = JSON.stringify(config)
def load_config
config = JSON.parse(global.localStorage.fuzzyhome_config)
def err s, e
p e
window.alert("Error {s}:\n\n{e}")
def reload_db def reload_db
state.links = await db.reload! state.links = await db.links.toArray()
sort_links! sort_links!
def can_add
return no if loading_add
return no if settings_active
await get_valid_link(state.query)
def sort_links def sort_links
if state.query.trim!.length > 0 if state.query.trim!.length > 0
state.scored_links = fzy state.links, state.query state.scored_links = fzi state.links, state.query
else else
state.scored_links = sortBy(state.links) do |link| state.scored_links = orderBy(state.links, 'frequency', 'desc')
-link.frequency
def increment_link_frequency link
try
await db.links.update link.id, { frequency: link.frequency + 1 }
catch e
err "putting link", e
def navigate link def toggle_settings
window.location.href = "//{link.link}" settings_active = !settings_active
def update_link link def increment_selection_index
link.last_opened = Date.now! selection_index = Math.min(state.scored_links.length - 1, selection_index + 1)
link.frequency = link.frequency + 1
await db.put link
def handle_click_link link def decrement_selection_index
update_link link selection_index = Math.max(0, selection_index - 1)
def use_search_engine def increment_search_engine_frequency
state.config.search_engine_frequency += 1 config.search_engine.frequency += 1
save_config! save_config!
let encoded_query = window.encodeURIComponent(state.query)
window.location.href = "//{state.config.search_engine_url}{encoded_query}"
def handle_return get encoded_search_query
if state.scored_links.length < 1 let encoded_query = window.encodeURIComponent(state.query)
use_search_engine! "{config.search_engine.url}{encoded_query}"
else
let link = state.scored_links[selection_index]
update_link link
navigate link
def handle_shift_return
use_search_engine!
def name_exists query def use_search_engine
for { name } in state.links increment_search_engine_frequency!
if query.trim!.toLowerCase! === name.trim!.toLowerCase! window.location.href = "//{encoded_search_query}"
return yes
return no
def fetch_image_as_base_64 url def fetch_image_as_base_64 url
let fallback = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAH0lEQVR42mO8seXffwYqAsZRA0cNHDVw1MBRA0eqgQCDRkbJSQHxEQAAAABJRU5ErkJggg==' let fallback = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAH0lEQVR42mO8seXffwYqAsZRA0cNHDVw1MBRA0eqgQCDRkbJSQHxEQAAAABJRU5ErkJggg=='
@ -114,143 +145,174 @@ tag app
return return
reader.readAsDataURL(blob) reader.readAsDataURL(blob)
def handle_click_create def get_valid_link text
loading_create = yes text = text.trim!
let query = state.query.trim! return no if text === ''
let split_text = text.split(/\s+/)
if query === '' return no if split_text.length < 2
loading_create = no let url = split_text.pop!
return let name = split_text.join(" ")
{ name, url }
split_query = query.split /\s+/ def strip_url url
url.trim!.replace(/(^\w+:|^)\/\//, '')
if split_query.length < 2 def add_link { url, name, frequency=1 }
loading_create = no name = name.trim!
return url = strip_url url
let img = await fetch_image_as_base_64(url)
let link = { name, url, frequency, img }
try
await db.links.put(link)
await reload_db!
catch e
err "adding link", e
let link = split_query.pop! def handle_click_link link
let name = split_query.join(" ") increment_link_frequency link
await put_link { link, name }
state.query = ''
reload_db!
loading_create = no
def can_put_link text def handle_click_search
let split_text = text.trim!.split(/\s+/) increment_search_engine_frequency!
return no if split_text.length < 2
split_text.pop!
let name = split_text.join " "
return no if name_exists name
return no if name.toLowerCase! === 'search'
yes
def put_link { link, name, frequency=1, last_opened=Date.now! } def handle_return
name = name.trim! if state.scored_links.length < 1
return if name_exists name use_search_engine!
return if name.toLowerCase! === 'search' else
link = link.trim!.replace(/(^\w+:|^)\/\//, '') let link = state.scored_links[selection_index]
let url = new URL("https://{link}") increment_link_frequency link
let img = await fetch_image_as_base_64(url.hostname) window.location.href = "//{link.url}"
await db.put { name, link, frequency, last_opened, img }
def handle_click_add
loading_add = yes
let link = await get_valid_link(state.query)
unless link
err "adding link", "Invalid link."
return
await add_link(link)
state.query = ''
sort_links!
loading_add = no
def handle_input def handle_input
selection_index = 0 selection_index = 0
sort_links! sort_links!
def handle_click_delete link def handle_click_delete link
return unless link
return unless window.confirm "Do you really want to delete {link..name}?" return unless window.confirm "Do you really want to delete {link..name}?"
await db.delete link try
await db.links.delete(link.id)
catch e
err "deleting link", e
state.query = '' state.query = ''
reload_db! try
await reload_db!
catch e
err "reloading db after successful delete", e
def handle_click_import e def handle_click_import e
loading_import = yes loading_import = yes
let data = await upload_json_file e let id_exists = do |newid|
state.links.some! do |{id}| newid === id
unless Array.isArray(data) let filter = do |table, value, key|
loading_import = no table === 'links' and not id_exists value.id
return try
await reload_db!
for link in data await db.import(e.target.files[0], { filter })
await put_link(link) await reload_db!
catch e
reload_db! err "importing db", e
loading_import = no loading_import = no
settings_active = no settings_active = no
def set_search_engine url
let hostname = new URL("https://{url}").hostname
let icon = await fetch_image_as_base_64 hostname
config.search_engine = { url, hostname, icon }
save_config!
def handle_click_export def handle_click_export
download_json_file JSON.stringify(state.links), "fuzzyhome_" let datetime = new Date!.toString!.split(" ")
let date = datetime.slice(1, 4).join("-").toLowerCase!
let time = datetime[4].split(":").join("-")
let filename = "fuzzyhome_{date}_{time}.json"
const blob = await db.export({ prettyJson: yes })
download(blob, filename, "application/json")
settings_active = no settings_active = no
def save_config
global.localStorage.fuzzyhome_config = JSON.stringify(state.config)
def load_config
state.config = JSON.parse(global.localStorage.fuzzyhome_config)
def handle_click_config def handle_click_config
let link = window.prompt("Please enter the URL of your search engine.") let input = window.prompt("Please enter the URL of your search engine.")
return unless link let url = input.trim!.replace(/(^\w+:|^)\/\//, '')
link = link.trim!.replace(/(^\w+:|^)\/\//, '') unless url
let url = new URL("https://{link}") err "changing search engine", "Invalid URL."
state.config.search_engine_icon = await fetch_image_as_base_64 url.hostname return
state.config.search_engine_url = link set_search_engine url
state.config.search_engine_hostname = url.hostname
save_config!
settings_active = no settings_active = no
def handle_click_github
global.location.href = "https://github.com/familyfriendlymikey/fuzzyhome"
def handle_paste e def handle_paste e
return if state.query.length > 0 return if state.query.length > 0
global.setTimeout(&, 0) do global.setTimeout(&, 0) do
window.location.href = "//{state.config.search_engine_url}{state.query.trim!}" use_search_engine!
def toggle_settings
if settings_active
settings_active = no
else
settings_active = yes
def increment_selection_index get pretty_date
selection_index = Math.min(state.links.length - 1, selection_index + 1) Date!.toString!.split(" ").slice(0, 4).join(" ")
def decrement_selection_index
selection_index = Math.max(0, selection_index - 1)
def render def render
<self> <self>
css body
d:flex fld:column jc:flex-start ai:center
m:0 w:100% h:100% bg:#20222f
ff:sans-serif fw:1
user-select:none
css self css self
d:flex fld:column jc:flex-start ai:center d:flex fld:column jc:flex-start ai:center
w:80vw max-width:700px max-height:80vh
bxs:0px 0px 10px rgba(0,0,0,0.35) bxs:0px 0px 10px rgba(0,0,0,0.35)
w:80vw h:auto max-width:700px box-sizing:border-box p:30px rd:10px mt:10vh
p:30px box-sizing:border-box rd:10px
mt:10vh max-height:80vh
css .buttons
d:flex fld:row jc:space-around w:100% h:50px
bg:purple4/10 rd:5px
css .button css .fatal
d:flex fld:column jc:center ai:center c:blue2
bg:none c:purple4 bd:none cursor:pointer fl:1
fs:14px ff:sans-serif fw:1
css $input css $main-input
w:100% h:50px px:20px
fs:20px ta:center
bd:1px solid purple4 bd:1px solid purple4
w:100% h:50px ta:center fs:20px bg:none rd:5px bg:none c:blue3 caret-color:blue3
bc:purple4 outline:none c:blue3 caret-color:blue3 px:20px outline:none rd:5px
@focus bg:purple4/10 @focus bg:purple4/10
@placeholder fs:10px c:blue3 @placeholder fs:10px c:blue3
css .settings-container
d:flex fld:row jc:space-around ai:center
w:100% h:50px
bg:purple4/10 rd:5px
css .settings-button
d:flex fld:column jc:center ai:center fl:1
bg:none c:purple4 bd:none cursor:pointer fs:14px
css .middle-button
d:flex fld:column jc:center ai:center
h:35px c:purple4 fs:20px cursor:pointer
fs:20px
css .disabled
@important c:gray4 cursor:default
css .links css .links
d:flex fld:column jc:flex-start d:flex fld:column jc:flex-start
w:100% ofy:auto fl:1 w:100% ofy:auto
px:20px
css .link css .link
d:flex fld:row jc:space-between ai:center d:flex fld:row jc:space-between ai:center
px:15px py:10px rd:5px cursor:pointer px:15px py:10px rd:5px cursor:pointer c:blue3
css .link-left
d:flex fl:1
css .selected css .selected
bg:blue3/5 bg:blue3/5
@ -258,107 +320,95 @@ tag app
css a css a
td:none td:none
css .name
tt:capitalize c:blue3 fs:20px
css .frequency
fs:15px c:blue3
css .link-icon css .link-icon
mr:10px rd:3px h:20px w:20px bd:none w:20px h:20px mr:10px rd:3px
css .disabled
@important c:gray4 cursor:default
css .settings-or-create css .name
h:35px tt:capitalize fs:20px word-wrap:anywhere
d:flex fld:column jc:center ai:center
css .create
d:inline fs:20px c:purple4 cursor:pointer
css .toggle-settings css .link-right
fs:25px c:purple4 cursor:pointer d:inline mt:-10px d:flex fld:row jc:space-between ai:center w:70px
css .delete css .delete
o:0
px:7px rd:3px c:purple4 fs:15px cursor:pointer
bd:1px solid purple4/50 bd:1px solid purple4/50
px:7px rd:3px fs:15px
c:purple4 cursor:pointer o:0
css .selected .delete css .selected .delete
o:100 o:100
css .link-left css .frequency
d:flex fl:1 fs:15px
css .link-right if fatal_error
d:flex fld:row jc:space-between ai:center w:70px <.fatal>
"""
<[d:flex fld:column jc:space-between ai:center w:100%]> There was an error loading the database.
if settings_active This could be due to a user setting
<.buttons> disallowing local storage, or a random error.
if loading_import Consider refreshing.
<.button.disabled> "IMPORT" Check developer console for more information.
else """
<label.button>
"IMPORT"
<input[d:none]
@change=handle_click_import
@click=(this.value = '')
type="file"
>
<.button@click=handle_click_export> "EXPORT"
<.button@click=handle_click_config> "CONFIG"
<.button@click=(global.location.href="https://github.com/familyfriendlymikey/fuzzyhome")> "HELP"
else else
<[d:flex fld:row jc:space-between ai:center w:100%]> unless settings_active
<input$input <input$main-input
@hotkey('mod+k').capture=$input..focus
bind=state.query bind=state.query
placeholder="v{version}" placeholder=pretty_date
@hotkey('return').capture=handle_return @hotkey('return').capture=handle_return
@hotkey('shift+return').capture=handle_shift_return
@hotkey('esc').capture=$input..blur
@hotkey('down').capture=increment_selection_index @hotkey('down').capture=increment_selection_index
@hotkey('up').capture=decrement_selection_index @hotkey('up').capture=decrement_selection_index
@input=handle_input @input=handle_input
@paste=handle_paste @paste=handle_paste
@blur=this.focus
>
else
<.settings-container>
unless loading_import
<label.settings-button>
"IMPORT"
<input[d:none]
@change=handle_click_import
@click=(this.value = '')
type="file"
> >
<.settings-or-create>
if can_put_link(state.query) and not settings_active
if loading_create
<.create.disabled>
" +"
else else
<.create@click=handle_click_create> <.settings-button.disabled> "IMPORT"
" +" <.settings-button@click=handle_click_export> "EXPORT"
<.settings-button@click=handle_click_config> "CONFIG"
<.settings-button@click=handle_click_github> "GITHUB"
if state.query.trim!.split(/\s+/).length < 2
<.middle-button[mt:-10px py:5px fs:25px]@click=toggle_settings> "..."
elif await can_add!
<.middle-button@click=handle_click_add> "+"
else else
<.toggle-settings@click=toggle_settings> "..." <.middle-button.disabled> "+"
if state.scored_links.length > 0
<.links> <.links>
for obj, index in state.scored_links if state.scored_links.length > 0
for link, index in state.scored_links
<a.link <a.link
href="//{obj.link}" href="//{link.url}"
@pointerover=(selection_index = index) @pointerover=(selection_index = index)
@click=handle_click_link(obj) @click=handle_click_link(link)
.selected=(index == selection_index) .selected=(index == selection_index)
> >
<.link-left> <.link-left>
<img.link-icon height=20 width=20 src=obj.img> <img.link-icon src=link.img>
<.name> obj.name <.name> link.name
<.link-right> <.link-right>
<.delete@click.prevent.stop=handle_click_delete(obj)> "x" <.delete@click.prevent.stop=handle_click_delete(link)> "x"
<.frequency> obj.frequency <.frequency> link.frequency
else else
<.links> <a.link.selected
<.link> href="//{encoded_search_query}"
@click=handle_click_search
>
<.link-left> <.link-left>
<img.link-icon src=state.config.search_engine_icon> <img.link-icon src=config.search_engine.icon>
<.name[tt:none]> "Search {state.config.search_engine_hostname}" <.name[tt:none]> encoded_search_query
<.link-right[jc:flex-end]> <.link-right[jc:flex-end]>
<.frequency> state.config.search_engine_frequency <.frequency> config.search_engine.frequency
$input.focus! $main-input.focus!
imba.mount <app> imba.mount <app>

5
app/state.imba

@ -1,5 +0,0 @@
let state = {}
state.query = ''
state.links = []
state.scored_links = []
export default state

14
app/utils/download.imba

@ -1,14 +0,0 @@
def get_datetime_string
let obj = new Date!.toString!.split(" ")
let date = obj.slice(1, 4).join("-").toLowerCase!
let time = obj[4].split(":").join("-")
"{date}_{time}"
export default def download_json_file data, prefix=""
let element = document.createElement 'a'
element.setAttribute 'href', 'data:text/plain;charset=utf-8,' + window.encodeURIComponent(data)
element.setAttribute 'download', "{prefix}{get_datetime_string!}.json"
element.style.display = 'none'
document.body.appendChild element
element.click!
document.body.removeChild element

95
app/utils/fzy.imba

@ -1,95 +0,0 @@
let SCORE_MIN = -Infinity
let SCORE_MAX = Infinity
let SCORE_GAP_LEADING = -0.005
let SCORE_GAP_TRAILING = -0.005
let SCORE_GAP_INNER = -0.01
let SCORE_MATCH_CONSECUTIVE = 1.0
let SCORE_MATCH_SLASH = 0.9
let SCORE_MATCH_WORD = 0.8
let SCORE_MATCH_DOT = 0.6
def fzy arr, query, keyname="name"
let needle = query.trim!.toLowerCase!
return [] unless arr.length > 0
let scored = []
let M = new Array(100_000)
let D = new Array(100_000)
let B = new Array(100_000)
for obj in arr
continue unless obj.hasOwnProperty keyname
let haystack = obj[keyname].trim!.toLowerCase!
continue unless has_match needle, haystack
obj.fzy_score = score(needle, haystack, M, D, B)
sorted_insert obj, scored
scored
def score needle, haystack, M, D, match_bonus
let n = needle.length
let m = haystack.length
if n < 1 or m < 1
return SCORE_MIN
if n === m
return SCORE_MAX
if m > 1024
return SCORE_MIN
compute needle, haystack, M, D, match_bonus
M[(n - 1)*m + (m - 1)]
def compute needle, haystack, M, D, match_bonus
let n = needle.length
let m = haystack.length
precompute_bonus haystack, match_bonus
for i in [0 .. n - 1]
let prev_score = SCORE_MIN
let gap_score = i === n - 1 ? SCORE_GAP_TRAILING : SCORE_GAP_INNER
for j in [0 .. m - 1]
let ij = i*m + j
let pij = (i - 1)*m + (j - 1)
if needle[i] === haystack[j]
let score = SCORE_MIN
if i === 0
score = (j * SCORE_GAP_LEADING) + match_bonus[j]
elif j > 0
score = Math.max(M[pij] + match_bonus[j], D[pij] + SCORE_MATCH_CONSECUTIVE)
D[ij] = score
M[ij] = prev_score = Math.max(score, prev_score + gap_score)
else
D[ij] = SCORE_MIN
M[ij] = prev_score = prev_score + gap_score
def precompute_bonus haystack, match_bonus
let m = haystack.length
let last_ch = '/'
for i in [0 .. m - 1]
let ch = haystack[i]
if last_ch === '/'
match_bonus[i] = SCORE_MATCH_SLASH
elif last_ch === '-' || last_ch === '_' || last_ch === ' '
match_bonus[i] = SCORE_MATCH_WORD
elif last_ch === '.'
match_bonus[i] = SCORE_MATCH_DOT
else
match_bonus[i] = 0
last_ch = ch
def has_match needle, haystack
let i = 0
let n = -1
let letter
while letter = needle[i++]
if (n = haystack.indexOf(letter, n + 1)) === -1
return no
return yes
def sorted_insert elem, arr
let low = 0
let high = arr.length
while low < high
let mid = (low + high) >>> 1
if elem.fzy_score > arr[mid].fzy_score
high = mid
else
low = mid + 1
arr.splice(low, 0, elem)
export default fzy

94
app/utils/idb_wrapper.imba

@ -1,94 +0,0 @@
let p = console.log
class idb_wrapper
constructor db_name, table_name, version
db_name = db_name
table_name = table_name
version = version
openRequest = null
def open
openRequest = global.indexedDB.open(db_name, version)
openRequest.onupgradeneeded = do |event|
p "Upgrading from DB version {event.oldVersion} to {event.newVersion}."
let db = openRequest.result
switch event.oldVersion
when 0
db.createObjectStore(table_name, { keyPath: 'id', autoIncrement: true })
openRequest.onerror = do
p "Open db error."
openRequest.onsuccess = do
p "Open db success."
if global.navigator.storage and global.navigator.storage.persist
global.navigator.storage.persist!.then! do |persistent|
p "db is persistent: {persistent}"
def reload
let store
while yes
try
store = #get_store "readonly"
p "Get store success."
break
catch
p "Failed to get store, retrying."
await #sleep 10
let request = store.getAll!
return new Promise! do |resolve|
request.onsuccess = do
p "Load db success."
resolve request.result
imba.commit!
request.onerror = do
p "Load db error."
resolve no
def delete obj
let store = #get_store!
let request = store.delete(obj.id)
return new Promise! do |resolve|
request.onsuccess = do
p "deleted link: {obj}"
resolve no
request.onerror = do
p "Failed to delete link: {obj}"
resolve yes
def put obj
let store = #get_store!
let request = store.put(obj)
return new Promise! do |resolve|
request.onsuccess = do
p "Successfully put link: {obj}"
resolve request.result
request.onerror = do
p "Failed to put link: {obj}"
resolve no
def #get_store permission="readwrite"
let db = openRequest.result
let transaction = db.transaction(table_name, permission)
transaction.objectStore(table_name)
def #sleep ms
new Promise! do |resolve|
setTimeout resolve, ms
export default idb_wrapper

14
app/utils/upload.imba

@ -1,14 +0,0 @@
export default def upload_json_file e
return new Promise! do |resolve|
let files = e.target.files
resolve no if files.length < 1
let file = files[0]
let reader = new FileReader()
reader.onloadend = do
try
resolve JSON.parse(reader.result)
catch
resolve no
reader.onerror = do
resolve no
reader.readAsText(file)

2674
package-lock.json

File diff suppressed because it is too large

11
package.json

@ -1,6 +1,6 @@
{ {
"name": "fuzzyhome", "name": "fuzzyhome",
"version": "0.0.32", "version": "0.1.0",
"scripts": { "scripts": {
"start": "imba run -SMH --baseurl . -w server.imba", "start": "imba run -SMH --baseurl . -w server.imba",
"build-app": "rm -rf dist && imba build -SMH --baseurl . server.imba", "build-app": "rm -rf dist && imba build -SMH --baseurl . server.imba",
@ -11,8 +11,15 @@
"deploy": "npm run build && npm run pages" "deploy": "npm run build && npm run pages"
}, },
"dependencies": { "dependencies": {
"dexie": "^3.2.2",
"dexie-export-import": "^1.0.3",
"dexie-observable": "^3.0.0-beta.11",
"download": "^8.0.0",
"downloadjs": "^1.4.7",
"express": "^4.17.1", "express": "^4.17.1",
"fzi": "^1.0.0",
"imba": "^2.0.0-alpha.207", "imba": "^2.0.0-alpha.207",
"lodash": "^4.17.21" "lodash": "^4.17.21",
"nanoid": "^4.0.0"
} }
} }

2
sw.imba

@ -1,7 +1,7 @@
let p = console.log let p = console.log
const app_prefix = "fuzzyhome_cache" const app_prefix = "fuzzyhome_cache"
const version = "0.0.32" const version = "0.1.0"
const cache_name = "{app_prefix}-{version}" const cache_name = "{app_prefix}-{version}"

Loading…
Cancel
Save