Skip to content

Commit

Permalink
✨ Search with history, loading indicator and no result indicator #59
Browse files Browse the repository at this point in the history
  • Loading branch information
MarceauKa committed Nov 15, 2019
1 parent d051c54 commit fa9611c
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 26 deletions.
9 changes: 7 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@

## Added

- Add to links a link to archive.org (issue #57)
- Search with history, loading indicator and no result indicator (issue #59)
- Links now have a shortcut to archive.org (issue #57)

## Fixed

- Markdown editor on small devices (issue #55)
- Story: Markdown editor on small devices (issue #55)

## Changed

- New form actions "Save", "Save & New", "Save & View"
- Story is now displayed at full-width
- Cleaned some translations

## Removed

- Original shaarli import (issue #30)

# 1.2.30

⚠️ Update your Git remote URL: `git remote set-url origin https://github.com/MarceauKa/shaark.git`
Expand Down
2 changes: 1 addition & 1 deletion public/css/app.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion public/js/app.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions public/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"/js/app.js": "/js/app.js?id=218e39e7190acbbe87dc",
"/css/app.css": "/css/app.css?id=aefcc4bc23ee04d56b9e",
"/js/app.js": "/js/app.js?id=1b8c92198940ed3ecf91",
"/css/app.css": "/css/app.css?id=22f8db76d67a883c07c8",
"/js/manifest.js": "/js/manifest.js?id=3c768977c2574a34506e",
"/js/vendor.js": "/js/vendor.js?id=d01e65db03bef4cabb61"
}
114 changes: 94 additions & 20 deletions resources/js/components/Search.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
<template>
<form class="form-inline">
<input class="form-control w-100"
type="search"
ref="input"
:placeholder="__('Type / to search')"
v-model="query"
@keydown.down.stop="move('down')"
@keydown.up.stop="move('up')"
@keydown.enter.prevent.stop="redirect"
>
<div class="search-input-wrapper">
<input class="form-control"
type="search"
ref="input"
:placeholder="__('Type / to search')"
v-model="query"
@focus="focused = true"
@blur="focused = false"
@keydown.down.stop="move('down')"
@keydown.up.stop="move('up')"
@keydown.enter.prevent.stop="choose"
>
<div class="spinner-border spinner-border-sm text-info" role="status" v-if="loading"></div>
<span class="badge badge-info text-white" role="status" v-if="displayNoResultIndicator">
{{ __('No result') }}
</span>
</div>

<div class="list-group results mt-1"
:class="{'active': hasResults}"
:class="{'active': hasResults || displaySearchHistory}"
v-on-clickaway="hide"
>
<a class="list-group-item list-group-item-action"
:class="{'active': selected === item}"
v-for="item in history"
v-if="displaySearchHistory"
>
<span><i class="fas fa-history fa-fw mr-1"></i> {{ item }}</span>
</a>

<div class="list-group-item"
v-if="hasTagsResults"
>
<div><i class="fas fa-tags"></i> {{ __('Tags') }}</div>
<div>
<a v-for="result in results.tags"
class="btn btn-primary btn-sm mr-1"
v-if="hasTagsResults"
:href="result.url"
>
{{ result.name }}
Expand Down Expand Up @@ -63,10 +78,14 @@ export default {
results: {},
loading: false,
selected: null,
history: [],
focused: false,
}
},
mounted() {
this.fetchHistory();
document.addEventListener('keydown', (event) => {
let isEventSafe = (event) => {
return event.target.tagName !== 'INPUT'
Expand All @@ -93,6 +112,7 @@ export default {
if (response.status === 200) {
this.results = response.data;
this.selected = null;
this.addHistory(this.query);
}
}).catch((error) => {
this.loading = false;
Expand All @@ -106,28 +126,65 @@ export default {
this.selected = null;
},
redirect() {
if (this.selected) {
choose() {
if (this.selected && this.displaySearchHistory) {
this.query = this.selected;
}
if (this.selected && this.hasResults) {
window.location = this.selected.url;
}
},
move(direction) {
if (false === this.hasResults) {
this.selected = null;
if (this.displaySearchHistory) {
this.moveIn(this.history, direction);
return;
}
let posts = this.results.posts;
let current = this.selected ? posts.indexOf(this.selected) : null;
let last = posts.length - 1;
if (this.hasResults) {
this.moveIn(this.results.posts, direction);
return;
}
this.selected = null;
},
moveIn(items, direction) {
let current = this.selected ? items.indexOf(this.selected) : null;
let last = items.length - 1;
if (direction === 'down') {
this.selected = (current === null || current === last) ? posts[0] : posts[current + 1];
this.selected = (current === null || current === last) ? items[0] : items[current + 1];
}
if (direction === 'up') {
this.selected = (current === null || current === 0) ? posts[last] : posts[current - 1];
this.selected = (current === null || current === 0) ? items[last] : items[current - 1];
}
},
fetchHistory() {
let storage = localStorage.getItem('searchHistory') || null;
if (storage) {
try {
this.history = JSON.parse(storage);
} catch (e) {
console.log('Unable to parse search history from local storage');
}
}
},
addHistory(query) {
if (false === this.hasResults) {
return;
}
if (this.history.indexOf(query) === -1) {
this.history.unshift(query);
this.history = this.history.slice(0, 5);
localStorage.setItem('searchHistory', JSON.stringify(this.history));
}
},
},
Expand All @@ -146,6 +203,19 @@ export default {
hasPostsResults() {
return this.results.hasOwnProperty('posts')
&& this.results.posts.length > 0;
},
displaySearchHistory() {
return this.history.length > 0
&& this.query === null
&& this.focused;
},
displayNoResultIndicator() {
return this.query !== null
&& this.query.length >= 3
&& this.loading === false
&& false === this.hasResults;
}
},
Expand All @@ -154,6 +224,10 @@ export default {
if (value && value.length >= 3) {
this.search(value)
}
if (value.length === 0) {
this.hide();
}
}, 200),
}
}
Expand Down
1 change: 1 addition & 0 deletions resources/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"Is private?": "Ist privater?",

"Type / to search": "Tippe zur Suche",
"No result": "No result",

"Retrieving URL informations...": "Abrufen der URL-Informationen...",
"Title": "Titel",
Expand Down
1 change: 1 addition & 0 deletions resources/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"Is private?": "Privé ?",

"Type / to search": "Tapez / pour chercher",
"No result": "Aucun résultat",

"Retrieving URL informations...": "Récupération des informations...",
"Title": "Titre",
Expand Down
1 change: 1 addition & 0 deletions resources/lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"Is private?": "Is private?",

"Type / to search": "「/」で検索を始める",
"No result": "No result",

"Retrieving URL informations...": "URLの情報を読み込んでいます…",
"Title": "タイトル",
Expand Down
18 changes: 18 additions & 0 deletions resources/sass/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ nav.navbar {
padding-left: 1rem;
padding-right: 1rem;

div.search-input-wrapper {
position: relative;
width: 100%;
min-width: 100%;

input {
width: 100%;
min-width: 100%;
}

.badge,
.spinner-border {
position: absolute;
right: 1rem;
top: .75rem;
}
}

.results {
display: none;
z-index: 500;
Expand Down

0 comments on commit fa9611c

Please sign in to comment.