feat(input): extract datepicker popup into a window-layer overlay and enhance the code editor modal status UI
This commit is contained in:
@@ -508,23 +508,15 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
const toolbar = modal.shadowRoot?.querySelector('.modal-toolbar');
|
||||
if (!toolbar) return;
|
||||
|
||||
// Update language button text
|
||||
const langBtn = toolbar.querySelector('.language-button span');
|
||||
if (langBtn) langBtn.textContent = getLanguageLabel();
|
||||
|
||||
// Update word wrap button
|
||||
const wrapBtn = toolbar.querySelector('.wrap-btn') as HTMLElement;
|
||||
if (wrapBtn) {
|
||||
wrapBtn.classList.toggle('active', modalWordWrap === 'on');
|
||||
}
|
||||
if (wrapBtn) wrapBtn.classList.toggle('active', modalWordWrap === 'on');
|
||||
|
||||
// Update line numbers button
|
||||
const linesBtn = toolbar.querySelector('.lines-btn') as HTMLElement;
|
||||
if (linesBtn) {
|
||||
linesBtn.classList.toggle('active', modalShowLineNumbers);
|
||||
}
|
||||
if (linesBtn) linesBtn.classList.toggle('active', modalShowLineNumbers);
|
||||
|
||||
// Update copy button
|
||||
const copyBtn = toolbar.querySelector('.copy-btn') as HTMLElement;
|
||||
const copyIcon = copyBtn?.querySelector('dees-icon') as any;
|
||||
if (copyBtn && copyIcon) {
|
||||
@@ -532,13 +524,28 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
copyIcon.icon = modalCopySuccess ? 'lucide:Check' : 'lucide:Copy';
|
||||
}
|
||||
|
||||
// Update dropdown visibility
|
||||
const dropdown = toolbar.querySelector('.language-dropdown') as HTMLElement;
|
||||
if (dropdown) {
|
||||
dropdown.style.display = modalLanguageDropdownOpen ? 'block' : 'none';
|
||||
}
|
||||
if (dropdown) dropdown.style.display = modalLanguageDropdownOpen ? 'block' : 'none';
|
||||
};
|
||||
|
||||
// Helper to update footer UI
|
||||
const updateFooterUI = (modal: DeesModal) => {
|
||||
const footer = modal.shadowRoot?.querySelector('.modal-footer');
|
||||
if (!footer) return;
|
||||
|
||||
const cursorEl = footer.querySelector('.footer-cursor');
|
||||
const linesEl = footer.querySelector('.footer-lines');
|
||||
const langEl = footer.querySelector('.footer-lang');
|
||||
|
||||
if (cursorEl) cursorEl.textContent = `Ln ${modalCursorLine}, Col ${modalCursorCol}`;
|
||||
if (linesEl) linesEl.textContent = `${modalLineCount} line${modalLineCount !== 1 ? 's' : ''}`;
|
||||
if (langEl) langEl.textContent = getLanguageLabel();
|
||||
};
|
||||
|
||||
let modalCursorLine = 1;
|
||||
let modalCursorCol = 1;
|
||||
let modalLineCount = currentValue.split('\n').length;
|
||||
|
||||
const modal = await DeesModal.createAndShow({
|
||||
heading: this.label || 'Code Editor',
|
||||
width: 'fullscreen',
|
||||
@@ -549,9 +556,7 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(0 0% 7%)')};
|
||||
border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
||||
padding: 4px 12px;
|
||||
gap: 8px;
|
||||
}
|
||||
.modal-toolbar .toolbar-left {
|
||||
@@ -644,9 +649,30 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
}
|
||||
.modal-editor-wrapper {
|
||||
position: relative;
|
||||
height: calc(100vh - 175px);
|
||||
height: calc(100vh - 200px);
|
||||
width: 100%;
|
||||
}
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
height: 28px;
|
||||
font-size: 11px;
|
||||
color: ${cssManager.bdTheme('hsl(0 0% 45%)', 'hsl(0 0% 55%)')};
|
||||
border-top: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
||||
}
|
||||
.modal-footer .footer-left,
|
||||
.modal-footer .footer-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.modal-footer .footer-separator {
|
||||
width: 1px;
|
||||
height: 12px;
|
||||
background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
|
||||
}
|
||||
</style>
|
||||
<div class="modal-toolbar">
|
||||
<div class="toolbar-left">
|
||||
@@ -687,6 +713,16 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
.wordWrap=${modalWordWrap}
|
||||
></dees-workspace-monaco>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="footer-left">
|
||||
<span class="footer-cursor">Ln ${modalCursorLine}, Col ${modalCursorCol}</span>
|
||||
<div class="footer-separator"></div>
|
||||
<span class="footer-lines">${modalLineCount} line${modalLineCount !== 1 ? 's' : ''}</span>
|
||||
</div>
|
||||
<div class="footer-right">
|
||||
<span class="footer-lang">${getLanguageLabel()}</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
menuOptions: [
|
||||
{
|
||||
@@ -698,7 +734,6 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
{
|
||||
name: 'Save & Close',
|
||||
action: async (modalRef) => {
|
||||
// Get the editor content from the modal
|
||||
modalEditorElement = modalRef!.shadowRoot?.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
|
||||
if (modalEditorElement) {
|
||||
const editor = await modalEditorElement.editorDeferred.promise;
|
||||
@@ -715,17 +750,61 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
modalEditorElement = modal.shadowRoot?.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
|
||||
|
||||
// Apply custom Monaco theme for matching background
|
||||
if (modalEditorElement) {
|
||||
const editor = await modalEditorElement.editorDeferred.promise;
|
||||
const domtoolsInstance = await modalEditorElement.domtoolsPromise;
|
||||
|
||||
const applyModalTheme = (isBright: boolean) => {
|
||||
const bg = isBright ? '#ffffff' : '#0a0a0a';
|
||||
(window as any).monaco?.editor?.defineTheme?.('dees-light', {
|
||||
base: 'vs',
|
||||
inherit: true,
|
||||
rules: [],
|
||||
colors: { 'editor.background': bg },
|
||||
});
|
||||
(window as any).monaco?.editor?.defineTheme?.('dees-dark', {
|
||||
base: 'vs-dark',
|
||||
inherit: true,
|
||||
rules: [],
|
||||
colors: { 'editor.background': bg },
|
||||
});
|
||||
editor.updateOptions({ theme: isBright ? 'dees-light' : 'dees-dark' });
|
||||
};
|
||||
|
||||
applyModalTheme(domtoolsInstance.themeManager.goBrightBoolean);
|
||||
domtoolsInstance.themeManager.themeObservable.subscribe((goBright: boolean) => {
|
||||
applyModalTheme(goBright);
|
||||
});
|
||||
|
||||
// Track cursor position
|
||||
editor.onDidChangeCursorPosition((e) => {
|
||||
modalCursorLine = e.position.lineNumber;
|
||||
modalCursorCol = e.position.column;
|
||||
updateFooterUI(modal);
|
||||
});
|
||||
|
||||
// Track line count
|
||||
const model = editor.getModel();
|
||||
if (model) {
|
||||
modalLineCount = model.getLineCount();
|
||||
updateFooterUI(modal);
|
||||
model.onDidChangeContent(() => {
|
||||
modalLineCount = model.getLineCount();
|
||||
updateFooterUI(modal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Wire up toolbar event handlers
|
||||
const toolbar = modal.shadowRoot?.querySelector('.modal-toolbar');
|
||||
if (toolbar) {
|
||||
// Language button click
|
||||
const langBtn = toolbar.querySelector('.language-button');
|
||||
langBtn?.addEventListener('click', () => {
|
||||
modalLanguageDropdownOpen = !modalLanguageDropdownOpen;
|
||||
updateToolbarUI(modal);
|
||||
});
|
||||
|
||||
// Language option clicks
|
||||
const langOptions = toolbar.querySelectorAll('.language-option');
|
||||
langOptions.forEach((option) => {
|
||||
option.addEventListener('click', async () => {
|
||||
@@ -734,23 +813,21 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
modalLanguage = newLang;
|
||||
modalLanguageDropdownOpen = false;
|
||||
|
||||
// Update editor language
|
||||
const editor = await modalEditorElement.editorDeferred.promise;
|
||||
const model = editor.getModel();
|
||||
if (model) {
|
||||
(window as any).monaco.editor.setModelLanguage(model, newLang);
|
||||
const editorModel = editor.getModel();
|
||||
if (editorModel) {
|
||||
(window as any).monaco.editor.setModelLanguage(editorModel, newLang);
|
||||
}
|
||||
|
||||
// Update selected state
|
||||
langOptions.forEach(opt => opt.classList.remove('selected'));
|
||||
option.classList.add('selected');
|
||||
|
||||
updateToolbarUI(modal);
|
||||
updateFooterUI(modal);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Word wrap button
|
||||
const wrapBtn = toolbar.querySelector('.wrap-btn');
|
||||
wrapBtn?.addEventListener('click', async () => {
|
||||
modalWordWrap = modalWordWrap === 'on' ? 'off' : 'on';
|
||||
@@ -761,7 +838,6 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
updateToolbarUI(modal);
|
||||
});
|
||||
|
||||
// Line numbers button
|
||||
const linesBtn = toolbar.querySelector('.lines-btn');
|
||||
linesBtn?.addEventListener('click', async () => {
|
||||
modalShowLineNumbers = !modalShowLineNumbers;
|
||||
@@ -772,7 +848,6 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
updateToolbarUI(modal);
|
||||
});
|
||||
|
||||
// Copy button
|
||||
const copyBtn = toolbar.querySelector('.copy-btn');
|
||||
copyBtn?.addEventListener('click', async () => {
|
||||
if (modalEditorElement) {
|
||||
@@ -792,7 +867,6 @@ export class DeesInputCode extends DeesInputBase<string> {
|
||||
}
|
||||
});
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
if (modalLanguageDropdownOpen && !langBtn?.contains(e.target as Node)) {
|
||||
modalLanguageDropdownOpen = false;
|
||||
|
||||
Reference in New Issue
Block a user