585 lines
29 KiB
HTML
585 lines
29 KiB
HTML
<div class="page-editor-wrapper" x-data="editorState()">
|
|
<!-- Share/More dialogs (in content area, triggered by header buttons) -->
|
|
|
|
<!-- ═══════════ Share / Publish Dialog ═══════════ -->
|
|
<div
|
|
class="share-dialog"
|
|
x-show="shareOpen"
|
|
@click.outside="!_justOpened && (shareOpen = false)"
|
|
x-transition.opacity.scale.origin.top.right
|
|
>
|
|
<!-- Header with tabs -->
|
|
<div class="sd-header">
|
|
<button
|
|
class="sd-tab"
|
|
:class="{ active: shareTab === 'share' }"
|
|
@click="shareTab = 'share'"
|
|
>
|
|
Share
|
|
</button>
|
|
<button
|
|
class="sd-tab"
|
|
:class="{ active: shareTab === 'publish' }"
|
|
@click="shareTab = 'publish'"
|
|
>
|
|
Publish
|
|
<span class="sd-badge" x-show="pagePublished"></span>
|
|
</button>
|
|
<button class="sd-close" @click="shareOpen = false">
|
|
✕
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ═══════ SHARE TAB ═══════ -->
|
|
<div class="sd-body" x-show="shareTab === 'share'" x-transition>
|
|
<!-- Invite input -->
|
|
<div class="sd-invite-row">
|
|
<input
|
|
type="email"
|
|
class="sd-input"
|
|
placeholder="Add people, groups or emails..."
|
|
x-model="inviteEmail"
|
|
@keydown.enter="shareInvite()"
|
|
/>
|
|
<button class="sd-btn-primary" @click="shareInvite()">
|
|
Invite
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Context card (shown when independent permissions) -->
|
|
<div class="sd-context-card" x-show="false">
|
|
Share settings on this page are unlinked from parent
|
|
page
|
|
</div>
|
|
|
|
<!-- Participants list -->
|
|
<div class="sd-participants" x-show="accessList.length">
|
|
<template x-for="a in accessList" :key="a.email">
|
|
{% raw %}
|
|
<div class="sd-participant">
|
|
<div class="sd-participant-info">
|
|
<div
|
|
class="sd-avatar"
|
|
x-text="a.email[0].toUpperCase()"
|
|
></div>
|
|
<div>
|
|
<div
|
|
class="sd-participant-name"
|
|
x-text="a.email"
|
|
></div>
|
|
<div
|
|
class="sd-participant-email"
|
|
x-text="a.email"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
<button
|
|
class="sd-perm-btn"
|
|
@click="a.permOpen = !a.permOpen"
|
|
>
|
|
<span
|
|
x-text="a.permission === 'editor' ? 'Full access' : a.permission === 'commenter' ? 'Can comment' : 'Can view'"
|
|
></span>
|
|
▾
|
|
</button>
|
|
<div
|
|
class="sd-perm-menu"
|
|
x-show="a.permOpen"
|
|
@click.outside="a.permOpen = false"
|
|
>
|
|
<div
|
|
class="sd-perm-option"
|
|
:class="{ active: a.permission === 'editor' }"
|
|
@click="a.permission='editor'; a.permOpen=false"
|
|
>
|
|
<span>Can edit</span>
|
|
<span class="sd-perm-desc"
|
|
>Edit, suggest and comment</span
|
|
>
|
|
</div>
|
|
<div
|
|
class="sd-perm-option"
|
|
:class="{ active: a.permission === 'commenter' }"
|
|
@click="a.permission='commenter'; a.permOpen=false"
|
|
>
|
|
<span>Can comment</span>
|
|
<span class="sd-perm-desc"
|
|
>Suggest and comment only</span
|
|
>
|
|
</div>
|
|
<div
|
|
class="sd-perm-option"
|
|
:class="{ active: a.permission === 'viewer' }"
|
|
@click="a.permission='viewer'; a.permOpen=false"
|
|
>
|
|
<span>Can view</span>
|
|
<span class="sd-perm-desc"
|
|
>Read only</span
|
|
>
|
|
</div>
|
|
<div class="sd-perm-sep"></div>
|
|
<div
|
|
class="sd-perm-option danger"
|
|
@click="removeAccess(a.email); a.permOpen=false"
|
|
>
|
|
Remove
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endraw %}
|
|
</template>
|
|
</div>
|
|
|
|
<div class="sd-sep"></div>
|
|
|
|
<!-- General Access -->
|
|
<div class="sd-section">
|
|
<div class="sd-section-title">General access</div>
|
|
<div style="position: relative">
|
|
<button
|
|
class="sd-access-btn"
|
|
@click="accessMenuOpen = !accessMenuOpen"
|
|
>
|
|
<span
|
|
x-text="generalAccess === 'invited' ? 'Only people invited' : 'Anyone with the link'"
|
|
></span>
|
|
<span class="chevron-down">▾</span>
|
|
</button>
|
|
<div
|
|
class="sd-access-menu"
|
|
x-show="accessMenuOpen"
|
|
@click.outside="accessMenuOpen = false"
|
|
x-transition
|
|
>
|
|
<div
|
|
class="sd-perm-option"
|
|
:class="{ active: generalAccess === 'invited' }"
|
|
@click="generalAccess='invited'; accessMenuOpen=false"
|
|
>
|
|
<span>{{ fd_icon('lock',14) }} Only people invited</span>
|
|
<span class="sd-perm-desc"
|
|
>People need to be invited</span
|
|
>
|
|
</div>
|
|
<div
|
|
class="sd-perm-option"
|
|
:class="{ active: generalAccess === 'anyone' }"
|
|
@click="generalAccess='anyone'; accessMenuOpen=false"
|
|
>
|
|
<span>{{ fd_icon('globe',14) }} Anyone with the link</span>
|
|
<span class="sd-perm-desc"
|
|
>Can view the page</span
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Public permission when link is open -->
|
|
<div
|
|
x-show="generalAccess === 'anyone'"
|
|
style="
|
|
margin-top: 6px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
"
|
|
>
|
|
<span
|
|
style="
|
|
font-size: 13px;
|
|
color: var(--text-primary);
|
|
"
|
|
>Anyone with the link</span
|
|
>
|
|
<select class="sd-select-sm" x-model="publicPerm">
|
|
<option value="viewer">Can view</option>
|
|
<option value="commenter">Can comment</option>
|
|
<option value="editor">Can edit</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sd-sep"></div>
|
|
|
|
<!-- Footer -->
|
|
<div class="sd-footer">
|
|
<a href="#" class="sd-footer-link" @click.prevent
|
|
>? Learn about sharing</a
|
|
>
|
|
<button class="sd-footer-action" @click="copyPageLink">
|
|
{{ fd_icon("link",14) }} Copy link
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════ PUBLISH TAB ═══════ -->
|
|
<div
|
|
class="sd-body"
|
|
x-show="shareTab === 'publish'"
|
|
x-transition
|
|
>
|
|
<!-- Before publishing -->
|
|
<div x-show="!pagePublished" class="sd-publish-hero">
|
|
<div class="sd-publish-preview">
|
|
<div class="sd-preview-bar"></div>
|
|
<div class="sd-preview-title">
|
|
{{ fd_icon('globe',14) }} {{ page.title }}
|
|
</div>
|
|
</div>
|
|
<h3 class="sd-publish-heading">Publish to web</h3>
|
|
<p class="sd-publish-desc">
|
|
Make this page visible to anyone on the internet.
|
|
You can share the link with anyone.
|
|
</p>
|
|
<button
|
|
class="sd-btn-primary sd-btn-full"
|
|
@click="publishPage()"
|
|
>
|
|
Publish
|
|
</button>
|
|
<p class="sd-publish-note">
|
|
Your page will be visible to anyone with the link.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- After publishing -->
|
|
<div x-show="pagePublished">
|
|
<div class="sd-url-bar">
|
|
<span
|
|
style="font-size: 13px; color: var(--text-dim)"
|
|
>{{ workspace_key or 'flowdeck' }}</span
|
|
>
|
|
<input
|
|
type="text"
|
|
class="sd-url-input"
|
|
:value="publishedUrl || pageUrl"
|
|
readonly
|
|
@click="$event.target.select()"
|
|
/>
|
|
<button
|
|
class="sd-btn-primary"
|
|
style="
|
|
height: 32px;
|
|
padding: 0 12px;
|
|
font-size: 12px;
|
|
"
|
|
@click="copyPageLink"
|
|
>
|
|
Copy link
|
|
</button>
|
|
</div>
|
|
|
|
<div class="sd-sep"></div>
|
|
|
|
<!-- Settings list -->
|
|
<div class="sd-settings">
|
|
<div class="sd-setting-row">
|
|
<span>{{ fd_icon("link",14) }} Link expires</span>
|
|
<span style="color: var(--text-dim)"
|
|
>Never ▾</span
|
|
>
|
|
</div>
|
|
<div class="sd-setting-row">
|
|
<span>{{ fd_icon('search',14) }} Search engine indexing</span>
|
|
<span style="color: var(--text-dim)"
|
|
>Off ▾</span
|
|
>
|
|
</div>
|
|
<div class="sd-setting-row">
|
|
<span>{{ fd_icon("file",14) }} Allow duplicate as template</span>
|
|
<label class="toggle-switch sm">
|
|
<input type="checkbox" checked />
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="sd-setting-row">
|
|
<span>{{ fd_icon("edit",14) }} Allow editing</span>
|
|
<label class="toggle-switch sm">
|
|
<input
|
|
type="checkbox"
|
|
x-model="pubAllowEdit"
|
|
/>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="sd-setting-row">
|
|
<span>{{ fd_icon("message-square",14) }} Allow comments</span>
|
|
<label class="toggle-switch sm">
|
|
<input
|
|
type="checkbox"
|
|
x-model="pubAllowComments"
|
|
checked
|
|
/>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sd-sep"></div>
|
|
|
|
<button
|
|
class="sd-danger-btn"
|
|
@click="unpublishPage()"
|
|
>
|
|
Unpublish
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════ Activity Popover ═══════════ -->
|
|
<div class="activity-popover"
|
|
x-show="activityOpen"
|
|
@click.outside="!_justOpened && (activityOpen = false)"
|
|
x-transition.opacity.scale.origin.top.right
|
|
style="position:absolute;top:100%;right:0;margin-top:4px;background:var(--bg-modal);border:1px solid var(--border);border-radius:var(--radius-lg);box-shadow:var(--shadow-modal);z-index:1000;width:280px;padding:12px;">
|
|
<div style="font-size:12px;color:var(--text-secondary);margin-bottom:4px;">Edited <span x-text="timeAgo"></span></div>
|
|
<template x-if="pageCreated">
|
|
<div style="font-size:12px;color:var(--text-tertiary);">Created <span x-text="formatDate(pageCreated)"></span></div>
|
|
</template>
|
|
</div>
|
|
|
|
<!-- More menu dropdown -->
|
|
<div
|
|
class="more-menu"
|
|
x-show="moreOpen"
|
|
@click.outside="!_justOpened && (moreOpen = false)"
|
|
x-transition
|
|
>
|
|
<div class="more-menu-item" @click="exportOpen = !exportOpen">↗ Export <span style="margin-left:auto;font-size:10px;opacity:.6">▾</span></div>
|
|
<template x-if="exportOpen">
|
|
<div class="more-menu-sub">
|
|
<div class="more-menu-item" @click="exportPage('markdown')"> Markdown (.md)</div>
|
|
<div class="more-menu-item" @click="exportPage('html')"> HTML (.html)</div>
|
|
<div class="more-menu-item" @click="exportPage('pdf')"> PDF (.pdf)</div>
|
|
<div class="more-menu-item" @click="exportPage('site')"> Site statique (.zip)</div>
|
|
</div>
|
|
</template>
|
|
<div class="more-menu-item" @click="duplicatePage">
|
|
{{ fd_icon("copy",14) }} Duplicate
|
|
</div>
|
|
<div class="more-menu-item" @click="movePage">↗ Move to</div>
|
|
<div class="more-menu-sep"></div>
|
|
<div class="more-menu-item danger" @click="deletePage">
|
|
{{ fd_icon("trash",14) }} Move to Trash
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════ Move to Dialog ═══════════ -->
|
|
<div class="move-dialog"
|
|
x-show="moveOpen"
|
|
@click.outside="moveOpen = false"
|
|
x-transition.opacity.scale
|
|
style="position:absolute;top:100%;right:0;margin-top:4px;background:var(--bg-modal);border:1px solid var(--border);border-radius:var(--radius-lg);box-shadow:var(--shadow-modal);z-index:1000;width:320px;padding:16px;">
|
|
<h3 style="font-size:14px;margin-bottom:12px;">Move to workspace</h3>
|
|
<div x-show="moveLoading" style="color:var(--text-tertiary);text-align:center;padding:20px;">Loading...</div>
|
|
<div x-show="!moveLoading" style="max-height:240px;overflow-y:auto;">
|
|
<template x-for="ws in moveWorkspaces" :key="ws.id">
|
|
<div class="move-ws-item"
|
|
@click="doMove(ws.id)"
|
|
style="display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:6px;cursor:pointer;font-size:13px;">
|
|
<span>{{ fd_icon("folder",14) }}</span>
|
|
<span x-text="ws.name" style="flex:1;"></span>
|
|
<span style="font-size:11px;color:var(--text-tertiary);" x-text="ws.page_count + ' pages'"></span>
|
|
</div>
|
|
</template>
|
|
<div x-show="moveWorkspaces.length === 0" style="color:var(--text-tertiary);text-align:center;padding:12px;">
|
|
No workspaces available
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════ Page Content ═══════════ -->
|
|
<div class="page-cover-area">
|
|
<div class="page-title-block">
|
|
<span class="page-icon-emoji">{% if page.content_format == 'file' %}{{ fd_icon("paperclip",14) }}{% else %}{{ fd_icon("file",14) }}{% endif %}</span>
|
|
<div
|
|
class="page-title-input"
|
|
contenteditable="true"
|
|
id="_titleEl"
|
|
@input="dirty=true;save()"
|
|
@keydown.enter.prevent="focusBlock()"
|
|
@paste.prevent="pastePlain($event)"
|
|
spellcheck="false"
|
|
>
|
|
{{ page.title }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="blocks-container"
|
|
id="_blocksCt"
|
|
@click="onCtClick($event)"
|
|
></div>
|
|
<div
|
|
id="_slashMenu"
|
|
class="slash-menu"
|
|
style="display: none; position: fixed; z-index: 999"
|
|
></div>
|
|
|
|
<!-- ═══════════ @mention autocomplete (v4.9.0) ═══════════ -->
|
|
<div id="_mentionMenu" class="mention-menu"
|
|
style="display:none;position:fixed;z-index:1200;min-width:240px;max-height:280px;overflow-y:auto;
|
|
background:var(--bg-modal,#1f1f1f);border:1px solid var(--border,#333);border-radius:10px;
|
|
box-shadow:var(--shadow-modal);padding:6px;"></div>
|
|
|
|
<!-- ═══════════ Inline comment trigger on selection (v4.9.0) ═══════════ -->
|
|
<button type="button" id="_commentSelBtn"
|
|
style="display:none;position:fixed;z-index:1100;padding:7px 12px;font-size:13px;font-weight:600;
|
|
color:#fff;background:var(--accent,#2383E2);border:none;border-radius:8px;cursor:pointer;
|
|
box-shadow:0 4px 16px rgba(0,0,0,.35);" title="Comment on selection"
|
|
@click="window.E && window.E.commentOnSelection()">
|
|
💬 Comment
|
|
</button>
|
|
|
|
<!-- ═══════════ Comments drawer (v4.9.0) ═══════════ -->
|
|
<div class="comments-drawer" x-show="commentsOpen" x-cloak x-transition
|
|
style="position:fixed;top:var(--topbar-height,44px);right:0;bottom:0;width:320px;max-width:92vw;
|
|
background:var(--bg-primary,#1c1c1c);border-left:1px solid var(--border,#333);
|
|
box-shadow:-8px 0 30px rgba(0,0,0,.25);z-index:900;display:flex;flex-direction:column;">
|
|
<div class="comments-drawer-header"
|
|
style="display:flex;align-items:center;justify-content:space-between;padding:12px 16px;
|
|
border-bottom:1px solid var(--border,#333);font-weight:600;font-size:14px;">
|
|
<span>Comments</span>
|
|
<button type="button" class="topbar-btn" @click="toggleComments()" title="Close">✕</button>
|
|
</div>
|
|
<div class="comments-drawer-list" style="flex:1;overflow-y:auto;padding:12px 16px;">
|
|
<div x-show="comments.length === 0" style="text-align:center;color:var(--text-dim,#999);padding:32px 0;">
|
|
No comments yet. Select some text and click 💬 Comment.
|
|
</div>
|
|
<template x-for="c in comments" :key="c.id">
|
|
<div class="comment-thread" style="margin-bottom:18px;"
|
|
:style="c.anchor_block_id ? 'border-left:3px solid var(--accent);padding-left:10px;' : ''">
|
|
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px;">
|
|
<div style="width:22px;height:22px;border-radius:50%;background:#3A3A3A;color:#fff;
|
|
display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;"
|
|
:style="{ background: c.author && c.author.avatar_color ? c.author.avatar_color : '#3A3A3A' }">
|
|
<span x-text="(c.author ? (c.author.full_name || c.author.login || '?') : '?').charAt(0).toUpperCase()"></span>
|
|
</div>
|
|
<span style="font-size:12px;font-weight:600;" x-text="c.author ? (c.author.full_name || c.author.login) : 'Unknown'"></span>
|
|
<span style="font-size:11px;color:var(--text-dim,#999);margin-left:auto;" x-text="fmtTime(c.created_at)"></span>
|
|
</div>
|
|
<div style="font-size:13px;white-space:pre-wrap;margin-bottom:6px;" x-text="c.body"></div>
|
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
<button class="btn-sm" style="font-size:11px;" @click="resolveComment(c.id)"
|
|
x-text="c.resolved ? '↪ Reopen' : '✔ Resolve'"></button>
|
|
<button class="btn-sm" style="font-size:11px;" x-show="c.user_id === currentUserId"
|
|
@click="deleteComment(c.id)">🗑 Delete</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
<div class="comments-drawer-input" style="border-top:1px solid var(--border,#333);padding:12px 16px;">
|
|
<textarea x-model="commentDraft" rows="2"
|
|
placeholder="Add a comment... Use @ to mention someone."
|
|
style="width:100%;background:var(--bg-secondary,#2a2a2a);border:1px solid var(--border,#333);
|
|
border-radius:8px;color:var(--text);font-size:13px;padding:8px 10px;resize:none;outline:none;"></textarea>
|
|
<div style="display:flex;justify-content:flex-end;margin-top:8px;">
|
|
<button class="btn btn-primary" style="font-size:12px;padding:6px 14px;" @click="addPageComment()">Comment</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="format-toolbar"
|
|
x-show="fmt.open"
|
|
:style="{top:fmt.top+'px',left:fmt.left+'px'}"
|
|
@mousedown.prevent
|
|
>
|
|
<button @click="fmtApply('bold')"><strong>B</strong></button>
|
|
<button @click="fmtApply('italic')"><em>I</em></button>
|
|
<button @click="fmtApply('underline')"><u>U</u></button>
|
|
<button @click="fmtApply('strikeThrough')"><s>S</s></button>
|
|
<button @click="fmtLink()">{{ fd_icon("link",14) }}</button>
|
|
</div>
|
|
|
|
<!-- ═══════════ Copy Link Toast ═══════════ -->
|
|
<div
|
|
class="sd-toast"
|
|
x-show="toastVisible"
|
|
x-transition
|
|
x-text="toastMsg"
|
|
></div>
|
|
|
|
<!-- ═══════════ Get Started Toolbar (bottom) ═══════════ -->
|
|
<div
|
|
class="get-started-toolbar"
|
|
x-show="blocks.length === 1 && blocks[0].type === 'paragraph' && !blocks[0].content.trim()"
|
|
>
|
|
<span class="gs-label">Get started with</span>
|
|
<button
|
|
class="gs-pill"
|
|
@click="replaceBlock(0, 'paragraph');blocks[0].content='Ask AI to write...';render()"
|
|
>
|
|
<span class="gs-icon">{{ fd_icon("sparkles",14) }}</span> Ask AI
|
|
</button>
|
|
<button
|
|
class="gs-pill"
|
|
@click="replaceBlock(0, 'heading_1');blocks[0].content='AI Meeting Note';render()"
|
|
>
|
|
<span class="gs-icon">{{ fd_icon('edit',14) }}</span> AI meeting note
|
|
</button>
|
|
<button
|
|
class="gs-pill"
|
|
@click="createDatabase()"
|
|
>
|
|
<span class="gs-icon">{{ fd_icon("folder",14) }}</span> Database
|
|
</button>
|
|
<button
|
|
class="gs-pill"
|
|
@click="createForm()"
|
|
>
|
|
<span class="gs-icon">{{ fd_icon("copy",14) }}</span> Form
|
|
</button>
|
|
<button
|
|
class="gs-pill"
|
|
@click="gsMoreOpen = !gsMoreOpen"
|
|
>
|
|
<span class="gs-icon">{{ fd_icon("file",14) }}</span> Templates
|
|
</button>
|
|
<div style="position: relative">
|
|
<button class="gs-pill" @click="gsMoreOpen = !gsMoreOpen">
|
|
<span>⋯</span>
|
|
</button>
|
|
<div
|
|
class="gs-more-dropdown"
|
|
x-show="gsMoreOpen"
|
|
@click.outside="gsMoreOpen = false"
|
|
x-transition
|
|
>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon("bar-chart",14) }} Table
|
|
</div>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon("copy",14) }} Board
|
|
</div>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon('list',14) }} List
|
|
</div>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon("calendar",14) }} Timeline
|
|
</div>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon("calendar",14) }} Calendar
|
|
</div>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon("image",14) }} Gallery
|
|
</div>
|
|
<div class="gs-more-sep"></div>
|
|
<div class="gs-more-item" @click="gsMoreOpen=false">
|
|
{{ fd_icon("download",14) }} Import
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="editor-statusbar">
|
|
<span x-show="saving">Saving...</span>
|
|
<span x-show="!saving&&dirty">Unsaved</span>
|
|
<span x-show="!saving&&!dirty&&lastSaved"
|
|
>Saved <span x-text="lastSaved"></span
|
|
></span>
|
|
<span class="statusbar-right" x-text="blocks.length+' blocks'"></span>
|
|
</div>
|
|
</div>
|