3 changed files with 266 additions and 0 deletions
@ -0,0 +1,88 @@ |
|||
export class FileGroup extends HTMLElement { |
|||
textEn = { |
|||
addFile: 'Add File', |
|||
} |
|||
|
|||
textEs = { |
|||
addFile: 'Añadir archivo', |
|||
} |
|||
|
|||
constructor() { |
|||
super() |
|||
this.language = navigator.language |
|||
this.attachShadow({mode: 'open'}) |
|||
this.headerEl = document.createElement('div') |
|||
this.headerEl.classList.add('header') |
|||
this.contentEl = document.createElement('div') |
|||
this.contentEl.classList.add('content') |
|||
this.shadowRoot.appendChild(this.headerEl) |
|||
this.shadowRoot.appendChild(this.contentEl) |
|||
const bGroup = document.createElement( |
|||
'm-forms-button-group' |
|||
) |
|||
bGroup.addPrimary(this.text.addFile, () => { |
|||
this.addFile() |
|||
const btn = bGroup.primary |
|||
if (btn.scrollIntoViewIfNeeded) { |
|||
btn.scrollIntoViewIfNeeded() |
|||
} else { |
|||
btn.scrollIntoView() |
|||
} |
|||
}) |
|||
this.shadowRoot.appendChild(bGroup) |
|||
} |
|||
|
|||
connectedCallback() { |
|||
const style = document.createElement('style') |
|||
style.textContent = ` |
|||
:host { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: stretch; |
|||
} |
|||
div.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
} |
|||
div.files { |
|||
display: flex; |
|||
flex-direction: column; |
|||
flex-grow: 1; |
|||
overflow-y: auto; |
|||
} |
|||
` |
|||
this.shadowRoot.appendChild(style) |
|||
if (this.contentEl.childNodes.length === 0) { |
|||
this.addFile() |
|||
} |
|||
} |
|||
|
|||
addFile({name, data} = {}) { |
|||
const el = document.createElement('m-editor-file-view') |
|||
if (name !== undefined) { |
|||
el.name = name |
|||
} |
|||
if (data !== undefined) { |
|||
el.data = data |
|||
} |
|||
this.contentEl.appendChild(el) |
|||
return el |
|||
} |
|||
|
|||
get language() { |
|||
return this._language |
|||
} |
|||
|
|||
set language(language) { |
|||
this._language = language |
|||
this.text = this.langEs ? this.textEs : this.textEn |
|||
} |
|||
|
|||
get langEs() { |
|||
return /^es\b/.test(this.language) |
|||
} |
|||
|
|||
get files() { |
|||
return [...this.contentEl.children] |
|||
} |
|||
} |
|||
@ -0,0 +1,120 @@ |
|||
export class FileView extends HTMLElement { |
|||
icons = { |
|||
menu: ` |
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-three-dots" viewBox="0 0 16 16"> |
|||
<path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/> |
|||
</svg> |
|||
`,
|
|||
} |
|||
|
|||
textEn = { |
|||
delete: 'Delete', |
|||
} |
|||
|
|||
textEs = { |
|||
delete: 'Borrar', |
|||
} |
|||
|
|||
constructor() { |
|||
super() |
|||
this.language = navigator.language |
|||
this.attachShadow({mode: 'open'}) |
|||
this.headerEl = document.createElement('div') |
|||
this.headerEl.classList.add('header') |
|||
this.contentEl = document.createElement('div') |
|||
this.contentEl.classList.add('content') |
|||
this.shadowRoot.appendChild(this.headerEl) |
|||
this.shadowRoot.appendChild(this.contentEl) |
|||
this.nameEl = document.createElement('input') |
|||
this.nameEl.classList.add('name') |
|||
this.headerEl.appendChild(this.nameEl) |
|||
this.editEl = document.createElement('m-editor-text-edit') |
|||
this.contentEl.appendChild(this.editEl) |
|||
this.menuBtn = document.createElement('button') |
|||
this.menuBtn.innerHTML = this.icons.menu |
|||
this.menuBtn.addEventListener('click', () => { |
|||
this.menu.open(this.menuBtn) |
|||
}) |
|||
this.headerEl.appendChild(this.menuBtn) |
|||
this.menu = document.createElement( |
|||
'm-menu-dropdown' |
|||
) |
|||
this.menu.add('Borrar', () => { |
|||
this.remove() |
|||
}) |
|||
this.shadowRoot.appendChild(this.menu) |
|||
} |
|||
|
|||
connectedCallback() { |
|||
const style = document.createElement('style') |
|||
style.textContent = ` |
|||
:host { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: stretch; |
|||
} |
|||
div.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: stretch; |
|||
background-color: #111; |
|||
color: #ddd; |
|||
padding: 3px 0; |
|||
} |
|||
div.header > * { |
|||
background: inherit; |
|||
color: inherit; |
|||
border: none; |
|||
} |
|||
.name { |
|||
flex-grow: 1; |
|||
padding: 0 5px; |
|||
font: inherit; |
|||
font-family: monospace; |
|||
outline: none; |
|||
} |
|||
div.header button svg { |
|||
margin-bottom: -3px; |
|||
} |
|||
div.content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: stretch; |
|||
} |
|||
svg { |
|||
height: 20px; |
|||
width: 20px; |
|||
} |
|||
` |
|||
this.shadowRoot.appendChild(style) |
|||
} |
|||
|
|||
set name(name) { |
|||
this.nameEl.value = name |
|||
} |
|||
|
|||
get name() { |
|||
return this.nameEl.value |
|||
} |
|||
|
|||
set data(data) { |
|||
this.editEl.value = data |
|||
} |
|||
|
|||
get data() { |
|||
return this.editEl.value |
|||
} |
|||
|
|||
get language() { |
|||
return this._language |
|||
} |
|||
|
|||
set language(language) { |
|||
this._language = language |
|||
this.text = this.langEs ? this.textEs : this.textEn |
|||
} |
|||
|
|||
get langEs() { |
|||
return /^es\b/.test(this.language) |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
export class TextEdit extends HTMLElement { |
|||
constructor() { |
|||
super() |
|||
this.attachShadow({mode: 'open'}) |
|||
this.stackEl = document.createElement('div') |
|||
this.stackEl.classList.add('stack') |
|||
this.textEl = document.createElement('textarea') |
|||
this.textEl.classList.add('text') |
|||
this.textEl.rows = 1 |
|||
this.stackEl.appendChild(this.textEl) |
|||
this.shadowRoot.appendChild(this.stackEl) |
|||
this.textEl.addEventListener('input', () => { |
|||
this.stackEl.dataset.copy = this.textEl.value |
|||
}) |
|||
} |
|||
|
|||
connectedCallback() { |
|||
// https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/
|
|||
const style = document.createElement('style') |
|||
style.textContent = ` |
|||
:host { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: stretch; |
|||
margin: 5px 0; |
|||
} |
|||
div.stack { |
|||
display: grid; |
|||
} |
|||
div.stack::after { |
|||
content: attr(data-copy) " "; |
|||
visibility: hidden; |
|||
overflow: hidden; |
|||
} |
|||
div.stack::after, div.stack > textarea { |
|||
white-space: pre-wrap; |
|||
border: 1px solid #888; |
|||
padding: 3px; |
|||
font: inherit; |
|||
font-family: monospace; |
|||
grid-area: 1 / 1 / 2 / 2; |
|||
min-height: 1em; |
|||
border-radius: 2px; |
|||
resize: none; |
|||
} |
|||
` |
|||
this.shadowRoot.appendChild(style) |
|||
} |
|||
|
|||
set value(value) { |
|||
this.textEl.value = value |
|||
this.stackEl.dataset.copy = this.textEl.value |
|||
} |
|||
|
|||
get value() { |
|||
return this.textEl.value |
|||
} |
|||
} |
|||
Loading…
Reference in new issue