mirror of
https://github.com/garraflavatra/rolens.git
synced 2025-07-18 22:04:05 +00:00
Context menu + database dropping
This commit is contained in:
58
frontend/src/components/contextmenu.svelte
Normal file
58
frontend/src/components/contextmenu.svelte
Normal file
@ -0,0 +1,58 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
|
||||
export let items = undefined;
|
||||
export let position = undefined;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function close() {
|
||||
dispatch('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if items && position}
|
||||
<div class="backdrop" on:pointerdown={close}></div>
|
||||
<ul class="contextmenu" role="" style:left="{position[0]}px" style:top="{position[1]}px">
|
||||
{#each items as item}
|
||||
{#if item.separator}
|
||||
<hr />
|
||||
{:else}
|
||||
<li>
|
||||
<button class="item" on:click={item.fn}>
|
||||
{item.label}
|
||||
</button>
|
||||
</li>
|
||||
{/if}
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.contextmenu {
|
||||
position: fixed;
|
||||
background-color: rgba(230, 230, 230, 0.7);
|
||||
backdrop-filter: blur(30px);
|
||||
border-radius: 10px;
|
||||
padding: 5px;
|
||||
box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #00008b;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
@ -1,9 +1,11 @@
|
||||
<script>
|
||||
import { contextMenu } from '../stores';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import Icon from './icon.svelte';
|
||||
|
||||
export let columns = [];
|
||||
export let items = [];
|
||||
export let actions = [];
|
||||
export let key = 'id';
|
||||
export let activeKey = '';
|
||||
export let activeChildKey = '';
|
||||
@ -12,7 +14,7 @@
|
||||
export let contained = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const childrenOpen = {};
|
||||
let childrenOpen = {};
|
||||
|
||||
$: _items = objectToArray(items).map(item => {
|
||||
item.children = objectToArray(item.children);
|
||||
@ -43,12 +45,32 @@
|
||||
dispatch('selectChild', childKey);
|
||||
}
|
||||
|
||||
function toggleChildren(itemKey) {
|
||||
function toggleChildren(itemKey, closeAll) {
|
||||
childrenOpen[itemKey] = !childrenOpen[itemKey];
|
||||
if (closeAll) {
|
||||
childrenOpen = {};
|
||||
dispatch('closeAll');
|
||||
}
|
||||
}
|
||||
|
||||
function showContextMenu(evt, item) {
|
||||
select(item[key]);
|
||||
contextMenu.show(evt, item.menu);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class:grid={level === 0} class:subgrid={level > 0} class:contained>
|
||||
{#if actions?.length}
|
||||
<div class="actions">
|
||||
{#each actions as action}
|
||||
<button class="btn" on:click={action.fn}>
|
||||
{#if action.icon}<Icon name={action.icon} />{/if}
|
||||
{action.label || ''}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<table>
|
||||
{#if showHeaders && columns.some(col => col.title)}
|
||||
<thead>
|
||||
@ -63,10 +85,15 @@
|
||||
|
||||
<tbody>
|
||||
{#each _items as item (item[key])}
|
||||
<tr on:click={() => select(item[key])} class:selected={activeKey === item[key] && !activeChildKey}>
|
||||
<tr
|
||||
on:click={() => select(item[key])}
|
||||
on:dblclick={() => toggleChildren(item[key])}
|
||||
on:contextmenu|preventDefault={evt => showContextMenu(evt, item)}
|
||||
class:selected={activeKey === item[key] && !activeChildKey}
|
||||
>
|
||||
<td class="has-toggle">
|
||||
{#if item.children?.length}
|
||||
<button class="toggle" on:click={() => toggleChildren(item[key])}>
|
||||
<button class="toggle" on:click={evt => toggleChildren(item[key], evt.shiftKey)}>
|
||||
<Icon name={childrenOpen[item[key]] ? 'chev-d' : 'chev-r'} />
|
||||
</button>
|
||||
{/if}
|
||||
@ -94,6 +121,7 @@
|
||||
items={item.children}
|
||||
level={level + 1}
|
||||
on:select={e => selectChild(item[key], e.detail)}
|
||||
on:closeAll={() => (childrenOpen = {})}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@ -116,6 +144,15 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-bottom: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.actions button {
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
export let name;
|
||||
export let name = '';
|
||||
</script>
|
||||
|
||||
{#if name === 'radio'}
|
||||
@ -14,6 +14,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-database"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"></path><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"></path></svg>
|
||||
{:else if name === 'x'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
||||
{:else if name === '+'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||
{:else if name === '-'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-minus"><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||
{:else if name === 'reload'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-refresh-cw"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>
|
||||
{/if}
|
||||
|
Reference in New Issue
Block a user