forked from EduCraft/curriculum-project-hub
feat(filelib-web): 老师端文件库改网盘式网格浏览(下钻导航+右键菜单)
- 新 GridLibraryView:双击下钻文件夹/项目,面包屑+返回跳级,项目内文件同网格, 双击进 FileEditor 预览;工具条按上下文出新建文件夹/项目/文件 - 右键菜单(ContextMenu):打开/新建子文件夹/重命名/授权管理/详情/删除, 按节点 role 动态显隐;文件菜单:打开预览/下载/删除;空白处右键出新建+刷新 - GridCard 大图标卡片(琥珀文件夹/立方体项目/文档文件);授权与详情复用 GrantsPanel/OverviewPanel(Modal 加 maxW prop);Icon 补 5 个图标 - 管理后台 /database 保留树状 LibraryView 不动;后端零改动
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<script lang="ts" module>
|
||||
import type { IconName } from "./Icon.svelte";
|
||||
|
||||
export interface MenuItem {
|
||||
readonly label: string;
|
||||
readonly icon?: IconName;
|
||||
readonly danger?: boolean;
|
||||
readonly onclick: () => void;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* 通用右键菜单:光标处弹出,点任意处/再次右键关闭。
|
||||
* 位置做视口夹取(右侧/底部溢出时向内收)。
|
||||
*/
|
||||
import Icon from "./Icon.svelte";
|
||||
|
||||
let { x, y, items, onclose }: { x: number; y: number; items: readonly MenuItem[]; onclose: () => void } = $props();
|
||||
|
||||
const MENU_W = 178;
|
||||
const ITEM_H = 34;
|
||||
const px = $derived(
|
||||
typeof window === "undefined" ? x : Math.max(4, Math.min(x, window.innerWidth - MENU_W - 8)),
|
||||
);
|
||||
const py = $derived(
|
||||
typeof window === "undefined" ? y : Math.max(4, Math.min(y, window.innerHeight - items.length * ITEM_H - 20)),
|
||||
);
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="fixed inset-0 z-50"
|
||||
role="presentation"
|
||||
onclick={onclose}
|
||||
oncontextmenu={(e) => { e.preventDefault(); onclose(); }}
|
||||
>
|
||||
<div
|
||||
class="fixed rounded-xl border border-line-soft bg-panel py-1.5 shadow-[0_8px_28px_rgba(26,26,24,.12)]"
|
||||
style="left:{px}px;top:{py}px;width:{MENU_W}px"
|
||||
>
|
||||
{#each items as item (item.label)}
|
||||
<button
|
||||
class="flex w-full items-center gap-2.5 px-3.5 py-[7px] text-left text-[12.5px] transition {item.danger
|
||||
? 'text-danger hover:bg-hover'
|
||||
: 'text-ink hover:bg-hover'}"
|
||||
onclick={() => { onclose(); item.onclick(); }}
|
||||
>
|
||||
{#if item.icon}
|
||||
<span class={item.danger ? "" : "text-ink-3"}><Icon name={item.icon} size={14} /></span>
|
||||
{/if}
|
||||
{item.label}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user