Files
numolus/app/frontend/components/FormulaSuggest.vue
T
wkhandClaude Opus 5.5 e14bada114 Add Rails backend: accounts via magic link, server documents, sharing
The app becomes a Rails 8 application; the Vue frontend moves to
app/frontend and is served through vite_rails.

- Without an account documents stay in the browser (IndexedDB). Sign-in
  is by magic link or the 6-digit code from the same mail; afterwards
  local documents can be uploaded into the account.
- Server documents (/d/<id>) with versioned saves and a single-editor
  lock per browser tab; others see them read-only and follow by polling.
- Sharing via link (works without an account) and via e-mail invitation,
  roles viewer/editor; the owner manages links and people.
- Store gains a read-only mode that blocks all content changes.
- Solid Queue, Cache and Cable share the one PostgreSQL database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:09:06 +02:00

72 lines
1.8 KiB
Vue

<script setup lang="ts">
/**
* Generic name/function autocomplete dropdown -- used both for a formula
* editor's function-name autocomplete (see useFormulaAutocomplete.ts) and
* the Name Box's table/sheet/named-range autocomplete (see document.ts's
* `nameBoxSuggestions()`), anything shaped like {name, hint}. Purely
* presentational -- positions itself just under whatever it's rendered
* inside of (that parent needs `position: relative`); no caret-pixel
* tracking.
*/
defineProps<{ items: { name: string; hint: string }[]; activeIndex: number }>();
const emit = defineEmits<{ (e: 'pick', index: number): void }>();
</script>
<template>
<ul class="formula-suggest" role="listbox">
<li
v-for="(item, i) in items"
:key="item.name"
role="option"
:aria-selected="i === activeIndex"
:class="{ on: i === activeIndex }"
@mousedown.prevent="emit('pick', i)"
>
<span class="name">{{ item.name }}</span>
<span class="hint">{{ item.hint }}</span>
</li>
</ul>
</template>
<style scoped>
.formula-suggest {
position: absolute;
top: 100%;
left: 0;
z-index: 30;
margin: 2px 0 0;
padding: 4px;
min-width: 220px;
max-width: 420px;
max-height: 220px;
overflow-y: auto;
list-style: none;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
font-size: 12px;
}
.formula-suggest li {
display: flex;
align-items: baseline;
gap: 8px;
padding: 5px 8px;
border-radius: 5px;
cursor: pointer;
white-space: nowrap;
}
.formula-suggest li.on {
background: var(--accent-weak);
}
.name {
font-weight: 600;
color: var(--text);
}
.hint {
color: var(--text-dim);
overflow: hidden;
text-overflow: ellipsis;
}
</style>