JSFiddle - React, Tailwind, and code Playground

by jcreamer898

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.0.0.debug.js"></script>
<div class="caret-container"><div class="caret"></div></div>
<!--
div.paragraph
    div.line
        div.line-background
        div.line-content
            span.line-wrapper
                span.bold
                span 
    div.line
    
-->
<div id="editor" data-bind="template: {
                name: 'paragraphTemplate',
                foreach: paragraphs }">
</div>

<script id="paragraphTemplate" type="text/html">
    <div class="paragraph" 
        data-bind="template: { foreach: lines, name: 'lineTemplate' }"></div>
</script>

<script id="lineTemplate" type="text/html">
    <div class="line" 
        data-bind="
        click: $root.activeLine,
        template: { foreach: contents, name: 'contentTemplate'}"></div>
</script>

<script id="contentTemplate" type="text/html">
    <span data-bind="text: content, click: $root.activeContent,"></span>
</script>

CSS

.caret-container { 
    position: absolute;
}

.caret {
    border-left: 2px solid black;
    opacity: 0;
    transition: opacity .13s ease-in;
    -webkit-transition: opacity .13s ease-in;
    min-height: 15.6px;
}

.caret-animating {
    opacity: 1;
}

JavaScript

var keyCodes = {
    '65': 'a',
    '66': 'b',
    '67': 'c',
    '68': 'd',
    '69': 'e',
    '70': 'f',
    '71': 'g',
    '72': 'h',
    '73': 'i',
    '74': 'j',
    '75': 'k',
    '76': 'l',
    '77': 'm',
    '78': 'n',
    '79': 'o',
    '80': 'p',
    '81': 'q',
    '82': 'r',
    '83': 's',
    '84': 't',
    '85': 'u',
    '86': 'v',
    '87': 'w',
    '88': 'x',
    '89': 'y',
    '90': 'z'
};

var caretContainer = document.getElementsByClassName('caret-container')[0],
    caret = caretContainer.firstChild,
    editor = document.getElementById('editor');

caretContainer.style.top = 0;
caretContainer.style.left = 0;

var each = function(arr, fn) {
    Array.prototype.forEach.call(arr, fn);
};

setInterval(function() {
    caret.className = ~caret.className.indexOf('animating') ? 'caret' : 'caret caret-animating';
}, 500);

var EditorViewModel = function(paragraphs) {
    this.activeLine = ko.observable();
    this.activeContent = ko.observable();

    this.paragraphs = ko.observableArray(paragraphs);  
};

var ParagraphViewModel = function(lines) {
    this.lines = ko.observableArray(lines);    
};

var LineViewModel = function(contents) {
    this.contents = ko.observableArray(contents);  
};

var ContentViewModel = function(content) {
    this.content = ko.observable(content);  
};

ko.bindingHandlers.editor = {
    init: function(el, valueAccessor, allBindings, data, context) {
        var value = valueAccessor(),
            paragraphs = value();

        ko.applyBindingsToNode(el, {
            
        });
    }
};



var vm = new EditorViewModel([
    new ParagraphViewModel([
        new LineViewModel([
            new ContentViewModel("hello world"),
            new ContentViewModel("wuttup?")        
        ]), 
        new LineViewModel([
            new ContentViewModel("hello"),
            new ContentViewModel("world")        
        ]), 
        new LineViewModel([
            new ContentViewModel("hello"),
            new...