Cartella con file per la frontend, un makefile per costruire tutto e lista utenti con fuzzy search
parent
91998e8924
commit
58db3e3901
@ -0,0 +1,36 @@
|
||||
|
||||
JS_SOURCES = $(wildcard frontend/src/*.js)
|
||||
JS_OUTPUTS = $(patsubst frontend/src/%.js, public/js/%.min.js, $(JS_SOURCES))
|
||||
SERVER_EXECUTABLE = phc-website-server
|
||||
|
||||
.PHONY: all
|
||||
all: js go
|
||||
|
||||
#
|
||||
# Build Frontend
|
||||
#
|
||||
|
||||
.PHONY: js
|
||||
js: $(JS_OUTPUTS)
|
||||
@echo "Compiled Frontend"
|
||||
|
||||
public/js/%.min.js: frontend/src/%.js
|
||||
cd frontend; rollup -c rollup.config.js
|
||||
cp $(patsubst frontend/src/%.js, frontend/dist/%.min.js, $<) $@
|
||||
|
||||
#
|
||||
# Build Server
|
||||
#
|
||||
|
||||
.PHONY: go
|
||||
go: $(SERVER_EXECUTABLE)
|
||||
@echo "Compiled Server"
|
||||
|
||||
$(SERVER_EXECUTABLE):
|
||||
go build -o $(SERVER_EXECUTABLE) .
|
||||
|
||||
.PHONY: debug
|
||||
debug:
|
||||
@echo "JS_SOURCES = $(JS_SOURCES)"
|
||||
@echo "JS_OUTPUTS = $(JS_OUTPUTS)"
|
||||
@echo "SERVER_EXECUTABLE = $(SERVER_EXECUTABLE)"
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||
"rollup": "^2.75.3",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"alpinejs": "^3.10.2",
|
||||
"fuse.js": "^6.6.2"
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'rollup'
|
||||
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
input: 'src/utenti.js',
|
||||
output: {
|
||||
file: 'dist/utenti.min.js',
|
||||
format: 'es',
|
||||
},
|
||||
plugins: [terser(), nodeResolve()],
|
||||
},
|
||||
])
|
@ -0,0 +1,82 @@
|
||||
import Alpine from 'alpinejs'
|
||||
import Fuse from 'fuse.js'
|
||||
|
||||
const SHOW_MORE_INCREMENT = 15
|
||||
const FUSE_OPTIONS = {
|
||||
includeScore: true,
|
||||
keys: [
|
||||
'nome',
|
||||
'cognome',
|
||||
{ name: 'nomeCompleto', getFn: user => `${user.nome} ${user.cognome}` },
|
||||
],
|
||||
}
|
||||
|
||||
const SORT_MODES = {
|
||||
chronological: () => 0,
|
||||
name: (a, b) => (a.nome < b.nome ? -1 : 1),
|
||||
surname: (a, b) => (a.cognome < b.cognome ? -1 : 1),
|
||||
}
|
||||
|
||||
function getSortedUserList(original, mode) {
|
||||
return [...original].sort(SORT_MODES[mode])
|
||||
}
|
||||
|
||||
Alpine.data('utenti', () => ({
|
||||
searchField: '', // two-way binding for the search input field
|
||||
sortMode: 'chronological', // two-way binding for the sorting mode
|
||||
fetchedUsers: [], // hold complete user list
|
||||
sortedUserBuffer: [], // Yet another buffer of the user list for the sort mode
|
||||
fuse: new Fuse([], FUSE_OPTIONS), // current fuse instance, used to filter the list above
|
||||
searchResultsBuffer: [], // stores the full current search
|
||||
searchResults: [], // list to renderer on screen with a subset of the whole search results buffer
|
||||
async init() {
|
||||
// Get user list from server
|
||||
const response = await fetch('/api/utenti')
|
||||
this.fetchedUsers = await response.json()
|
||||
|
||||
// This will call the function "showMore()" when the user is near the end of the list
|
||||
new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
console.log('Near the bottom of the page')
|
||||
this.showMore()
|
||||
}
|
||||
})
|
||||
}).observe(this.$refs.spinner)
|
||||
|
||||
// Initialize with an empty query
|
||||
this.updateSortMode()
|
||||
this.updateSearch()
|
||||
},
|
||||
showMore() {
|
||||
// setTimeout(() => {
|
||||
// Updates the final "searchResults" list with more items from the previous buffer
|
||||
const newCount = this.searchResults.length + SHOW_MORE_INCREMENT
|
||||
this.searchResults = this.searchResultsBuffer.slice(0, newCount)
|
||||
// }, 250) // For fun
|
||||
},
|
||||
setResults(list) {
|
||||
this.searchResultsBuffer = list.filter(
|
||||
entry => entry.score === undefined || entry.score <= 0.25
|
||||
)
|
||||
this.searchResults = this.searchResultsBuffer.slice(0, SHOW_MORE_INCREMENT)
|
||||
},
|
||||
updateSortMode() {
|
||||
this.sortedUserBuffer = getSortedUserList(this.fetchedUsers, this.sortMode)
|
||||
this.fuse.setCollection(this.sortedUserBuffer)
|
||||
this.updateSearch()
|
||||
},
|
||||
updateSearch() {
|
||||
console.time('search')
|
||||
if (this.searchField.trim().length === 0) {
|
||||
// Reset the result list
|
||||
this.setResults(this.sortedUserBuffer.map(user => ({ item: user })))
|
||||
} else {
|
||||
// Update the result list with the new results
|
||||
this.setResults(this.fuse.search(this.searchField))
|
||||
}
|
||||
console.timeEnd('search')
|
||||
},
|
||||
}))
|
||||
|
||||
Alpine.start()
|
@ -1,3 +0,0 @@
|
||||
// window.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
// })
|
Loading…
Reference in New Issue