diff --git a/app/api.imba b/app/api.imba index c2de245..7f27a19 100644 --- a/app/api.imba +++ b/app/api.imba @@ -8,6 +8,7 @@ import config from './config' import { omit, orderBy } from 'lodash' import { nanoid } from 'nanoid' import fzi from 'fzi' +import { evaluate as eval_math } from 'mathjs' export default new class api @@ -177,3 +178,30 @@ export default new class api def navigate link await increment_link_frequency link window.location.href = link.url + + get math_result + try + let result = Number(eval_math state.query) + throw _ if isNaN result + throw _ if result.toString! is state.query.trim! + result + catch + no + + def handle_cut e + return unless e.target.selectionStart == e.target.selectionEnd + let s = math_result + s ||= state.query + await window.navigator.clipboard.writeText(s) + state.query = '' + sort_links! + + def handle_add_link + state.loading = yes + try + await add_link state.query + state.query = '' + sort_links! + catch e + err "adding link", e + state.loading = no diff --git a/app/client.imba b/app/client.imba index bbf26e0..1dc4ba8 100644 --- a/app/client.imba +++ b/app/client.imba @@ -15,6 +15,7 @@ let refs = {} import api from './api' import config from './config' +import './components/app-home' import './components/app-community-links' import './components/app-settings' import './components/app-prompt' @@ -52,7 +53,7 @@ tag app refs.settings = $as refs.edit = $ae refs.community-links = $acl - refs.links = $al + refs.links = $ah unless global.localStorage.fuzzyhome_visited await api.add_initial_links! @@ -69,7 +70,7 @@ tag app def render - css d:flex fld:column jc:flex-start ai:center + css d:flex fld:column jc:start ai:center w:80vw max-width:700px max-height:80vh bxs:0px 0px 10px rgba(0,0,0,0.35) box-sizing:border-box p:30px rd:10px mt:10vh @@ -95,6 +96,6 @@ tag app else - + imba.mount diff --git a/app/components/app-bang.imba b/app/components/app-bang.imba index 58c81b7..e4ad4d0 100644 --- a/app/components/app-bang.imba +++ b/app/components/app-bang.imba @@ -1,5 +1,9 @@ tag app-bang + get bang + return active_bang if state.active_bang + config.data.default_bang + get encoded_bang_query "{bang.url}{window.encodeURIComponent(state.query)}" @@ -9,27 +13,94 @@ tag app-bang def render - - css d:flex fld:row jc:space-between ai:center - px:16px py:11px rd:5px cursor:pointer c:#FAD4AB + + css w:100% d:flex fld:column gap:10px + + + + + <.tip-row> + + <.tip + @click=(state.active_bang = no) + @hotkey('esc').capture.if(!state.loading)=(state.active_bang = no) + > + <.tip-hotkey> "Return" + <.tip-content> "Search" + + <.tip + @click=api.handle_add_link + @hotkey('shift+return').capture.if(!state.loading)=api.handle_add_link + > + <.tip-hotkey> "Shift + Return" + <.tip-content.ellipsis> + "Create Link " + let sq = state.query.trim!.split /\s+/ + if sq.length >= 2 + let url = sq.pop! + '"' + sq.join " " + " {url}" + '"' + else + "\"{sq.join " "}\"" + + if state.active_bang + <.tip + @click=(state.active_bang = no) + @hotkey('esc').capture.if(!state.loading)=(state.active_bang = no) + > + <.tip-hotkey> "Esc" + <.tip-content> "Back" + else + <.tip + @click.if(!state.loading)=refs.settings.open + @hotkey('esc').capture.if(!state.loading)=refs.settings.open + > + <.tip-hotkey> "Esc" + <.tip-content> "Toggle Settings" + + + + <.tip-row> + + <.tip + @click.if(!state.loading)=api.toggle_effective_names + @hotkey('tab').capture.if(!state.loading)=api.toggle_effective_names + > + <.tip-hotkey> "Tab" + <.tip-content> "Toggle Effective Names" + + <.tip + @click.if(!loading)=api.handle_cut + > + if math_result + <.tip-hotkey> "Cut (Math, If No Selection)" + <.tip-content> "Cut Math Result" + else + <.tip-hotkey> "Cut (If No Selection)" + <.tip-content> "Cut All Text" + + <.tip.noclick> + <.tip-hotkey> "Paste (If Input Empty)" + <.tip-content> "Instant Search" + + unless $tips-more.active + <.bang.selected@click=handle_bang> + css d:flex fld:row jc:space-between ai:center + px:16px py:11px rd:5px cursor:pointer c:blue3 - <.link-left> - css d:flex fl:1 + <.link-left> + css d:flex fl:1 - - css w:20px h:20px mr:10px rd:3px + + css w:20px h:20px mr:10px rd:3px - <.display-name> encoded_bang_query - css tt:capitalize fs:20px overflow-wrap:anywhere - css tt:none word-break:break-all + <.display-name> encoded_bang_query + css c:#FAD4AB fs:20px word-break:break-all - <.link-right> - css d:flex fld:row jc:space-between ai:center - css .buttons-disabled .link-button visibility:hidden - css .selected .link-button visibility:visible + <.link-right> + css d:flex fld:row jc:space-between ai:center - <.frequency> bang.frequency - css fs:15px ml:7px + <.frequency> bang.frequency + css fs:15px ml:7px diff --git a/app/components/app-community-links.imba b/app/components/app-community-links.imba index b311236..9c3de74 100644 --- a/app/components/app-community-links.imba +++ b/app/components/app-community-links.imba @@ -38,7 +38,7 @@ tag app-community-links > css self - d:flex fld:column jc:flex-start fl:1 + d:flex fld:column jc:start fl:1 w:100% ofy:auto pt:15px css .link diff --git a/app/components/app-home.imba b/app/components/app-home.imba new file mode 100644 index 0000000..7f8b575 --- /dev/null +++ b/app/components/app-home.imba @@ -0,0 +1,86 @@ +tag app-home + + def mount + $links-input.focus! + + def handle_paste e + return unless config.data.enable_search_on_paste + return if state.query.length > 0 + global.setTimeout(&, 0) do + return if api.math_result isnt no + bang ||= config.data.default_bang + handle_bang! + + def handle_click_copy s + try + await window.navigator.clipboard.writeText(s) + state.query = '' + api.sort_links! + + def handle_input + api.set_link_selection_index 0 + api.sort_links! + + def handle_click_link + if state.active_bang or state.sorted_links.length < 1 + return handle_bang! + let link = api.selected_link + if link.is_bang + state.query = '' + state.active_bang = link + else + api.navigate link + + def handle_click_delete link + return unless window.confirm "Do you really want to delete {link..display_name}?" + handle_delete link + + def handle_click_pin link + api.pin_link link + + def handle_shift_backspace + return unless state.sorted_links.length > 0 + refs.edit.open api.selected_link + + def render + + + css w:100% d:flex fld:column gap:10px ofy:hidden + + <.header> + css d:flex fld:row w:100% + css .side c:purple3/90 fs:15px d:flex ja:center w:30px cursor:pointer + css .side svg w:15px d:flex + css .left jc:left + css .right jc:right + + <.side.left@click=api.toggle_effective_names> + + if config.data.enable_effective_names + + + else + + + + + if (let m = api.math_result) isnt no + <.side.right@click=handle_click_copy(m)> + "= {Math.round(m * 100)/100}" + css c:blue3 fs:20px ml:10px w:unset + + else + <.side.right @click.if(!state.loading)=refs.settings.open> + + + if state.active_bang or state.sorted_links.length < 1 + + + else + diff --git a/app/components/app-link.imba b/app/components/app-link.imba index 30906d4..3057aa4 100644 --- a/app/components/app-link.imba +++ b/app/components/app-link.imba @@ -33,7 +33,7 @@ tag app-link css .selected .link-button visibility:visible <.link-buttons .buttons-disabled=!config.data.enable_buttons> - css d:flex fld:row jc:flex-start ai:center pr:25px gap:5px + css d:flex fld:row jc:start ai:center pr:25px gap:5px css .link-button visibility:hidden rd:3px c:purple4 fs:15px cursor:pointer px:3px css .link-button svg w:15px diff --git a/app/components/app-links.imba b/app/components/app-links.imba index a1eecce..a89b2aa 100644 --- a/app/components/app-links.imba +++ b/app/components/app-links.imba @@ -1,263 +1,91 @@ -import { evaluate as eval_math } from 'mathjs' - tag app-links - def mount - $links-input.focus! - - def handle_paste e - return unless config.data.enable_search_on_paste - return if state.query.length > 0 - global.setTimeout(&, 0) do - return if math_result isnt no - bang ||= config.data.default_bang - handle_bang! - - def handle_click_copy s - try - await window.navigator.clipboard.writeText(s) - state.query = '' - api.sort_links! - - def handle_cut e - return unless e.target.selectionStart == e.target.selectionEnd - let s = math_result - s ||= state.query - await window.navigator.clipboard.writeText(s) - state.query = '' - api.sort_links! - - def handle_add - state.loading = yes - try - await api.add_link state.query - state.query = '' - api.sort_links! - catch e - err "adding link", e - state.loading = no - - get math_result - try - let result = Number(eval_math state.query) - throw _ if isNaN result - throw _ if result.toString! is state.query.trim! - result - catch - no - - def handle_input - api.set_link_selection_index 0 - api.sort_links! - - def handle_click_link - if state.active_bang or state.sorted_links.length < 1 - return handle_bang! - let link = api.selected_link - if link.is_bang - state.query = '' - state.active_bang = link - else - api.navigate link - - def handle_click_delete link - return unless window.confirm "Do you really want to delete {link..display_name}?" - handle_delete link - - def handle_click_pin link - api.pin_link link - - def handle_shift_backspace - return unless state.sorted_links.length > 0 - refs.edit.open api.selected_link - - def handle_shift_return - def go - if viewing_community_links - try - await add_community_link api.selected_link - catch e - err "adding community link", e - else - handle_add! - state.loading = yes - await go! - editing_link = no - state.query = '' - api.sort_links! - state.loading = no - - def toggle_settings - refs.settings.open! - def render - css w:100% d:flex fld:column gap:10px - - if $as.active - + css w:100% d:flex fld:column gap:10px ofy:hidden - else + - <.header> - css d:flex fld:row w:100% - css .side c:purple3/90 fs:15px d:flex ja:center w:30px cursor:pointer - css .side svg w:15px d:flex - css .left jc:left - css .right jc:right + <.tip-row> - <.side.left@click=api.toggle_effective_names> - - if config.data.enable_effective_names - - - else - - - + <.tip-hotkey> "Return" + <.tip-content> "Navigate To Link" - if (let m = math_result) isnt no - <.side.right@click=handle_click_copy(m)> - "= {Math.round(m * 100)/100}" - css c:blue3 fs:20px ml:10px w:unset - - else - <.side.right @click.if(!state.loading)=toggle_settings> - - - if state.active_bang or state.sorted_links.length < 1 - - - - <.tip-row> - - <.tip - @click=(state.active_bang = no) - @hotkey('esc').capture.if(!state.loading)=(state.active_bang = no) - > - <.tip-hotkey> "Esc" - <.tip-content> "Back" - - <.tip - @click=handle_shift_return - @hotkey('shift+return').capture.if(!state.loading)=handle_shift_return - > - <.tip-hotkey> "Shift + Return" - <.tip-content.ellipsis> - "Create Link " - let sq = state.query.trim!.split /\s+/ - if sq.length >= 2 - let url = sq.pop! - '"' - sq.join " " - " {url}" - '"' - else - "\"{sq.join " "}\"" - - <.tip - @click=(state.active_bang = no) - @hotkey('esc').capture.if(!state.loading)=(state.active_bang = no) - > - <.tip-hotkey> "Return" - <.tip-content> "Search" - - else - - - - <.tip-row> - - <.tip - @click=handle_click_link - @hotkey('return').force.if(!loading)=handle_click_link - > - <.tip-hotkey> "Return" - <.tip-content> "Navigate To Link" - - <.tip - @click=handle_shift_return - @hotkey('shift+return').capture.if(!state.loading)=handle_shift_return - > - <.tip-hotkey> "Shift + Return" - <.tip-content.ellipsis> - "Create Link " - let sq = state.query.trim!.split /\s+/ - if sq.length >= 2 - let url = sq.pop! - '"' - sq.join " " - " {url}" - '"' - else - "\"{sq.join " "}\"" - - <.tip - @click=handle_shift_backspace - @hotkey('shift+backspace').capture.if(!state.loading)=handle_shift_backspace - > - <.tip-hotkey> "Shift + Backspace" - <.tip-content> "Edit Link" + <.tip + @click=handle_shift_return + @hotkey('shift+return').capture.if(!state.loading)=handle_shift_return + > + <.tip-hotkey> "Shift + Return" + <.tip-content.ellipsis> + "Create Link " + let sq = state.query.trim!.split /\s+/ + if sq.length >= 2 + let url = sq.pop! + '"' + sq.join " " + " {url}" + '"' + else + "\"{sq.join " "}\"" + + <.tip + @click=handle_shift_backspace + @hotkey('shift+backspace').capture.if(!state.loading)=handle_shift_backspace + > + <.tip-hotkey> "Shift + Backspace" + <.tip-content> "Edit Link" - + - <.tip-row> + <.tip-row> - <.tip - @click.if(!state.loading)=api.toggle_effective_names - @hotkey('tab').capture.if(!state.loading)=api.toggle_effective_names - > - <.tip-hotkey> "Tab" - <.tip-content> "Toggle Effective Names" + <.tip + @click.if(!state.loading)=api.toggle_effective_names + @hotkey('tab').capture.if(!state.loading)=api.toggle_effective_names + > + <.tip-hotkey> "Tab" + <.tip-content> "Toggle Effective Names" - <.tip - @click.if(!state.loading)=api.toggle_settings - @hotkey('esc').capture.if(!state.loading)=toggle_settings - > - <.tip-hotkey> "Esc" - <.tip-content> "Toggle Settings" + <.tip + @click.if(!state.loading)=refs.settings.open + @hotkey('esc').capture.if(!state.loading)=refs.settings.open + > + <.tip-hotkey> "Esc" + <.tip-content> "Toggle Settings" - <.tip.noclick - @hotkey('down').capture.if(!state.loading)=api.increment_link_selection_index - @hotkey('up').capture.if(!state.loading)=api.decrement_link_selection_index - > - <.tip-hotkey> "Up/Down Arrow" - <.tip-content> "Move Selection" + <.tip.noclick + @hotkey('down').capture.if(!state.loading)=api.increment_link_selection_index + @hotkey('up').capture.if(!state.loading)=api.decrement_link_selection_index + > + <.tip-hotkey> "Up/Down Arrow" + <.tip-content> "Move Selection" - <.tip-row> + <.tip-row> - <.tip - @click.if(!loading)=handle_cut - > - if math_result - <.tip-hotkey> "Cut (Math, If No Selection)" - <.tip-content> "Cut Math Result" - else - <.tip-hotkey> "Cut (If No Selection)" - <.tip-content> "Cut All Text" + <.tip + @click.if(!loading)=api.handle_cut + > + if api.math_result + <.tip-hotkey> "Cut (Math, If No Selection)" + <.tip-content> "Cut Math Result" + else + <.tip-hotkey> "Cut (If No Selection)" + <.tip-content> "Cut All Text" - <.tip.noclick> - <.tip-hotkey> "Paste (If Input Empty)" - <.tip-content> "Instant Search" + <.tip.noclick> + <.tip-hotkey> "Paste (If Input Empty)" + <.tip-content> "Instant Search" - <.tip.placeholder> + <.tip.placeholder> - unless $tips-more.active - <.links> - css d:flex fld:column jc:flex-start - fl:1 w:100% ofy:auto + unless $tips-more.active + <.links> + css ofy:scroll + for link, index in state.sorted_links + - if state.active_bang - - elif state.sorted_links.length < 1 - - else - for link, index in state.sorted_links - diff --git a/app/styles.imba b/app/styles.imba index 0a2cb3d..3cdff98 100644 --- a/app/styles.imba +++ b/app/styles.imba @@ -1,5 +1,5 @@ global css body - d:flex fld:column jc:flex-start ai:center + d:flex fld:column jc:start ai:center m:0 w:100% h:100% bg:#20222f ff:sans-serif fw:1 user-select:none