mirror of
https://github.com/PaiGramTeam/luoxu-api-pub.git
synced 2024-11-25 09:27:40 +00:00
select sender by name
This commit is contained in:
parent
a62d883a76
commit
dc4bc48302
@ -9,7 +9,6 @@ body {
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { onMount, setContext } from 'svelte'
|
||||
import Message from './Message.svelte'
|
||||
import Name from './Name.svelte'
|
||||
|
||||
const LUOXU_URL = 'https://lab.lilydjwg.me/luoxu'
|
||||
let groups = []
|
||||
@ -11,6 +12,7 @@
|
||||
let now = new Date()
|
||||
let loading = false
|
||||
let need_update_title = false
|
||||
let sender
|
||||
|
||||
setContext('LUOXU_URL', LUOXU_URL)
|
||||
|
||||
@ -153,6 +155,7 @@
|
||||
on:input={() => error = ''}
|
||||
on:keydown={e => {if(e.key == 'Enter'){do_search()}}}
|
||||
/>
|
||||
<Name group={group} selected={sender}/>
|
||||
<button on:click={() => do_search()}>搜索</button>
|
||||
</div>
|
||||
|
||||
@ -216,4 +219,18 @@
|
||||
border: 1px #bfbfbf solid;
|
||||
border-radius: 2em;
|
||||
}
|
||||
|
||||
:global(input), :global(button), :global(select) {
|
||||
border-radius: 0;
|
||||
border: 1px solid var(--color-inactive);
|
||||
height: 2.3em;
|
||||
}
|
||||
:global(input:focus), :global(button:focus), :global(select:focus) {
|
||||
border-color: var(--color-active);
|
||||
outline: 1px solid var(--color-active);
|
||||
}
|
||||
:global(:root) {
|
||||
--color-inactive: #bfbfbf;
|
||||
--color-active: #add8e6;
|
||||
}
|
||||
</style>
|
||||
|
188
src/Name.svelte
Normal file
188
src/Name.svelte
Normal file
@ -0,0 +1,188 @@
|
||||
<script>
|
||||
import { onMount, getContext } from 'svelte'
|
||||
|
||||
export let group
|
||||
|
||||
export let selected
|
||||
let selected_name = ''
|
||||
let selected_idx
|
||||
|
||||
let to
|
||||
let names = []
|
||||
let url = getContext('LUOXU_URL')
|
||||
let input
|
||||
let ul
|
||||
let has_focus = false
|
||||
let has_mouse = false
|
||||
|
||||
let abort = new AbortController()
|
||||
|
||||
onMount(() => {
|
||||
const rect = input.getBoundingClientRect()
|
||||
ul.style.top = `${rect.height - 1}px`
|
||||
ul.style.width = `${rect.width - 2}px`
|
||||
})
|
||||
|
||||
function may_complete() {
|
||||
if(to) {
|
||||
clearTimeout(to)
|
||||
}
|
||||
to = setTimeout(function(){
|
||||
complete_it()
|
||||
}, 300)
|
||||
}
|
||||
|
||||
async function complete_it() {
|
||||
if(!group || !input.value) {
|
||||
return
|
||||
}
|
||||
abort.abort()
|
||||
abort = new AbortController()
|
||||
try{
|
||||
const res = await fetch(`${url}/names?g=${group}&q=${input.value}`,
|
||||
{signal: abort.signal})
|
||||
const j = await res.json()
|
||||
if(!abort.aborted) {
|
||||
// only update if we're current
|
||||
names = j.names
|
||||
}
|
||||
}catch(e){
|
||||
if(e instanceof DOMException && e.name == 'AbortError'){
|
||||
}else{
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
if(ul) {
|
||||
if(names.length === 0 || (!has_focus && !has_mouse)) {
|
||||
ul.style.display = 'none'
|
||||
}else{
|
||||
ul.style.display = 'block'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function select_by_click(e) {
|
||||
let el = e.target
|
||||
if(el.tagName == 'IMG') {
|
||||
el = el.parentNode
|
||||
}
|
||||
if(el.tagName != 'LI') {
|
||||
return
|
||||
}
|
||||
selected_idx = el.dataset.idx
|
||||
select_confirmed()
|
||||
}
|
||||
|
||||
function select_confirmed() {
|
||||
selected = names[selected_idx][0]
|
||||
selected_name = names[selected_idx][1]
|
||||
input.value = selected_name
|
||||
}
|
||||
|
||||
function update_value() {
|
||||
if(input.value) {
|
||||
input.value = selected_name
|
||||
}else{
|
||||
selected = null
|
||||
selected_name = ''
|
||||
}
|
||||
}
|
||||
|
||||
function select_by_key(e) {
|
||||
if(e.key == 'ArrowDown' || (e.key == 'n' && e.altKey)) {
|
||||
select_next(1)
|
||||
e.preventDefault()
|
||||
}else if(e.key == 'ArrowUp' || (e.key == 'p' && e.altKey)) {
|
||||
select_next(-1)
|
||||
e.preventDefault()
|
||||
}else if(e.key == 'Enter') {
|
||||
select_confirmed()
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
function select_next(dir) {
|
||||
if(typeof selected_idx === 'number') {
|
||||
if(dir > 0) {
|
||||
selected_idx = (selected_idx + 1) % names.length
|
||||
}else{
|
||||
selected_idx = (selected_idx - 1) % names.length
|
||||
}
|
||||
}else{
|
||||
if(dir > 0) {
|
||||
selected_idx = 0
|
||||
}else{
|
||||
selected_idx = names.length - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: NOT operator
|
||||
</script>
|
||||
|
||||
<div on:mouseenter={() => has_mouse=true} on:mouseleave={() => has_mouse=false}>
|
||||
<input bind:this={input} type="text" on:input={may_complete} on:focus={() => has_focus=true} on:blur={() => {has_focus=false;update_value()}} on:keydown={select_by_key}/>
|
||||
<img class="selected-avatar" alt="" src="{url}/avatar/{selected?selected:'nobody'}.jpg"/>
|
||||
<ul bind:this={ul} on:click={select_by_click}>
|
||||
{#each names as name, i (name)}
|
||||
<li data-idx={i} class:selected={i===selected_idx} title={name[1]}><img src="{url}/avatar/{name[0]}.jpg" alt="avatar"/>{name[1]}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
display: none;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 4px var(--color-inactive);
|
||||
clip-path: polygon(-100% 0, 200% 0, 200% 200%, -100% 200%);
|
||||
}
|
||||
li {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
line-height: 2em;
|
||||
}
|
||||
li > img {
|
||||
height: calc(2.3em - 2px);
|
||||
width: calc(2.3em - 2px);
|
||||
vertical-align: middle;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
ul:not(:hover) > li.selected, li:hover {
|
||||
background-color: #d9f5ff;
|
||||
}
|
||||
input {
|
||||
padding-left: 2.5em;
|
||||
}
|
||||
input, ul {
|
||||
border-radius: 0;
|
||||
border: 1px solid var(--color-inactive);
|
||||
}
|
||||
input:focus, input:focus ~ ul {
|
||||
border-color: var(--color-active);
|
||||
box-shadow: 0 0 4px var(--color-active);
|
||||
outline: 1px solid var(--color-active);
|
||||
}
|
||||
input:focus ~ ul {
|
||||
border-top-color: var(--color-inactive);
|
||||
}
|
||||
.selected-avatar {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
height: calc(2.3em - 2px);
|
||||
width: calc(2.3em - 2px);
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user