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>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user