Excel
<!DOCTYPE html><html lang="en">    <head>        <meta charset="UTF-8" />        <meta name="viewport" content="width=device-width, initial-scale=1.0" />        <meta author="MiduDev" />        <meta url="midudev" />        <meta author="ShunTrDev" />        <title>Excel.js</title>        <style>            body {                font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,                    'Open Sans', 'Helvetica Neue', sans-serif;            }
            *,            *::before,            *::after {                box-sizing: border-box;            }
            img {                max-width: 20px;                height: auto;            }
            table {                border-collapse: collapse;            }
            thead,            tr td:first-child {                background: #eee;            }
            th,            td {                border: 1px solid #ccc;                font-weight: normal;                font-size: 12px;                text-align: center;                width: 64px;                height: 20px;                vertical-align: middle;                position: relative;            }
            /* td:active {            border-radius: 2px;            outline: 2px solid #09f;            } */
            span,            input {                position: absolute;                inset: 0;                vertical-align: middle;                display: inline-flex;                justify-content: center;                align-items: center;            }
            input {                border: 0;                opacity: 0;                pointer-events: none;                width: 100%;                border-radius: 2px;
                &:focus {                    opacity: 1;                    outline: 2px solid #09f;                }            }
            .selected {                background: rgb(174, 223, 255);            }
            th.selected {                background: rgb(146, 211, 255);            }        </style>        <script type="module">            const $ = (el) => document.querySelector(el)            const $$ = (el) => document.querySelectorAll(el)
            const $table = $('table')            const $head = $('thead')            const $body = $('tbody')
            const ROWS = 10            const COLUMNS = 5            const FIRST_CHAR_CODE = 65
            const times = (length) => Array.from({ length }, (_, i) => i)            const getColumn = (i) => String.fromCharCode(FIRST_CHAR_CODE + i)
            let selectedColumn = null
            let STATE = times(COLUMNS).map((i) => times(ROWS).map((j) => ({ computedValue: 0, value: 0 })))
            console.log(STATE)
            function updateCell({ x, y, value }) {                const newState = structuredClone(STATE)                const constants = generateCellsConstants(newState)
                const cell = newState[x][y]
                cell.computedValue = computeValue(value, constants) // -> span                cell.value = value // -> input
                newState[x][y] = cell
                computeAllCells(newState, generateCellsConstants(newState))
                STATE = newState
                renderSpreadSheet()            }
            function generateCellsConstants(cells) {                return cells                    .map((rows, x) => {                        return rows                            .map((cell, y) => {                                const letter = getColumn(x) // -> A                                const cellId = `${letter}${y + 1}` // -> A1                                return `const ${cellId} = ${cell.computedValue};`                            })                            .join('\n')                    })                    .join('\n')            }
            function computeAllCells(cells, constants) {                console.log('computeAllCells')                cells.forEach((rows, x) => {                    rows.forEach((cell, y) => {                        const computedValue = computeValue(cell.value, constants)                        cell.computedValue = computedValue                    })                })            }
            function computeValue(value, constants) {                if (typeof value === 'number') return value                if (!value.startsWith('=')) return value
                const formula = value.slice(1)
                let computedValue                try {                    computedValue = eval(`(() => {        ${constants}            return ${formula};        })()`)                } catch (e) {                    computedValue = `!ERROR: ${e.message}`                }
                console.log({ value, computedValue })
                return computedValue            }
            const renderSpreadSheet = () => {                const headerHTML = `<tr>                    <th></th>                    ${times(COLUMNS)                        .map((i) => `<th>${getColumn(i)}</th>`)                        .join('')}                </tr>`
                $head.innerHTML = headerHTML
                const bodyHTML = times(ROWS)                    .map((row) => {                        return `<tr>                            <td>${row + 1}</td>                            ${times(COLUMNS)                                .map(                                    (column) => `                            <td data-x="${column}" data-y="${row}">                                <span>${STATE[column][row].computedValue}</span>                                <input type="text" value="${STATE[column][row].value}" />                            </td>                            `                                )                                .join('')}                        </tr>`                    })                    .join('')
                $body.innerHTML = bodyHTML            }
            $body.addEventListener('click', (event) => {                const td = event.target.closest('td')                if (!td) return
                const { x, y } = td.dataset                const input = td.querySelector('input')                const span = td.querySelector('span')
                const end = input.value.length                input.setSelectionRange(end, end)                input.focus()
                $$('.selected').forEach((el) => el.classList.remove('selected'))                selectedColumn = null
                input.addEventListener('keydown', (event) => {                    if (event.key === 'Enter') input.blur()                })
                input.addEventListener(                    'blur',                    () => {                        console.log({ value: input.value, state: STATE[x][y].value })
                        if (input.value === STATE[x][y].value) return
                        updateCell({ x, y, value: input.value })                    },                    { once: true }                )            })
            $head.addEventListener('click', (event) => {                const th = event.target.closest('th')                if (!th) return
                const x = [...th.parentNode.children].indexOf(th)                if (x <= 0) return
                selectedColumn = x - 1
                $$('.selected').forEach((el) => el.classList.remove('selected'))                th.classList.add('selected')                $$(`tr td:nth-child(${x + 1})`).forEach((el) => el.classList.add('selected'))            })
            document.addEventListener('keydown', (event) => {                if (event.key === 'Backspace' && selectedColumn !== null) {                    times(ROWS).forEach((row) => {                        updateCell({ x: selectedColumn, y: row, value: '' })                    })                    renderSpreadSheet()                }            })
            document.addEventListener('copy', (event) => {                if (selectedColumn !== null) {                    const columnValues = times(ROWS).map((row) => {                        return STATE[selectedColumn][row].computedValue                    })
                    event.clipboardData.setData('text/plain', columnValues.join('\n'))                    event.preventDefault()                }            })
            document.addEventListener('click', (event) => {                const { target } = event
                const isThClicked = target.closest('th')                const isTdClicked = target.closest('td')
                if (!isThClicked && !isTdClicked) {                    $$('.selected').forEach((el) => el.classList.remove('selected'))                    selectedColumn = null                }            })
            renderSpreadSheet()        </script>    </head>
    <body>        <img            src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Microsoft_Excel_2013-2019_logo.svg/1200px-Microsoft_Excel_2013-2019_logo.svg.png" />
        <table>            <thead></thead>            <tbody></tbody>        </table>    </body></html>
<!--- Añadir la funconalidad de filas- Haz la suma por rangos=A1:A20- Seleccionar por celdas-->