Loquicom 6 months ago
commit
5250b735b4
19 changed files with 2062 additions and 0 deletions
  1. 83 0
      barnabus.html
  2. 0 0
      css/cmd.min.css
  3. BIN
      css/font/Halo-Covenant.ttf
  4. BIN
      css/font/JetBrainsMono-Regular.woff2
  5. 3 0
      css/pico.min.css
  6. 86 0
      css/splash.css
  7. 161 0
      css/style.css
  8. BIN
      favicon.ico
  9. 88 0
      index.php
  10. 891 0
      js/cmd.js
  11. 1 0
      js/jquery.min.js
  12. 151 0
      js/konami.js
  13. 17 0
      js/loaded.js
  14. 132 0
      js/pico8-cart.js
  15. 129 0
      js/script.js
  16. 72 0
      js/splash.js
  17. 164 0
      proto.html
  18. 57 0
      src/pico8.html
  19. 27 0
      src/splash.html

+ 83 - 0
barnabus.html

@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Glad.Os</title>
+        <link rel="stylesheet" type="text/css" href="css/cmd.min.css">
+        <link rel="stylesheet" type="text/css" href="css/style.css">
+        <link rel="icon" href="favicon.ico">
+    </head>
+    <body id="cmd" class="cmd-interface">
+
+        <div id="splash">
+            <div id="logo">
+                _____/\\\\\\\\\\\\__/\\\\\\___________________________/\\\______________/\\\\\___________________<br/>
+                &nbsp;___/\\\//////////__\////\\\__________________________\/\\\____________/\\\///\\\_________________<br/>
+                &nbsp;&nbsp;__/\\\________________\/\\\__________________________\/\\\__________/\\\/__\///\\\_______________<br/>
+                &nbsp;&nbsp;&nbsp;_\/\\\____/\\\\\\\____\/\\\_____/\\\\\\\\\___________\/\\\_________/\\\______\//\\\__/\\\\\\\\\\_<br/>
+                &nbsp;&nbsp;&nbsp;&nbsp;_\/\\\___\/////\\\____\/\\\____\////////\\\_____/\\\\\\\\\________\/\\\_______\/\\\_\/\\\//////__<br/>
+                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_\/\\\_______\/\\\____\/\\\______/\\\\\\\\\\___/\\\////\\\________\//\\\______/\\\__\/\\\\\\\\\\_<br/>
+                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_\/\\\_______\/\\\____\/\\\_____/\\\/////\\\__\/\\\__\/\\\_________\///\\\__/\\\____\////////\\\_<br/>
+                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_\//\\\\\\\\\\\\/___/\\\\\\\\\_\//\\\\\\\\/\\_\//\\\\\\\/\\__/\\\____\///\\\\\/______/\\\\\\\\\\_<br/>
+                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__\////////////____\/////////___\////////\//___\///////\//__\///_______\/////_______\//////////__<br/>
+                <br/>
+                <div id="version">V-8.2.6</div>
+            </div>
+    
+            <div id="text">
+                <p id="line-1" class="line hide">Connexion au serveur en cours...</p>
+                <br/>
+                <p id="line-2" class="line hide">Activation du mode CLI...</p>
+                <br/>
+                <p id="line-3" class="line hide">Succès !</p>
+            </div>
+    
+            <div id="loader"></div>
+            <div id="access" class="none">
+                <button>Accèder</button>
+            </div>
+        </div>
+
+        <div id="welcome" class="none">
+            Bienvenue Chell et bon retour sur Glad.os<br/>
+            &nbsp;&nbsp;Par Loquicom<br/>
+            <br/>
+            Le logiciel est livré sans garantie, ni assistance<br/>
+            Pour plus d'informations merci de consulter notre site<br/>
+            <br/>
+            Merci d'entrer une commande<br/>
+            Pour avoir une liste des commandes disponibles taper "aide"
+        </div>
+        
+        <script src="js/jquery.min.js"></script>
+        <script src="js/loader.js"></script>
+        <script src="js/script.js"></script>
+        <script src="js/cmd.js"></script>
+        <script>
+            $(() => {
+                const loaderInterval = loader();
+            
+                /* Annimation texte */
+                $('#line-1').removeClass('hide').addClass('anim-typewriter');
+                $('#line-1').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function() {
+                    $('#line-2').removeClass('hide').addClass('anim-typewriter');
+                });
+                $('#line-2').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function() {
+                    $('#line-3').removeClass('hide').addClass('anim-typewriter');
+                });
+                $('#line-3').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function() {
+                    $('#loader').addClass('none');
+                    $('#access').removeClass('none');
+                });
+
+                $('#access').on('click', function() {
+                    toggleFullScreen(document.getElementById('cmd'));
+                    clearInterval(loaderInterval);
+                    $('#splash').remove();
+                    $('#welcome').removeClass('none');
+                    cmd();
+                });
+            });
+        </script>
+    </body>
+</html>

File diff suppressed because it is too large
+ 0 - 0
css/cmd.min.css


BIN
css/font/Halo-Covenant.ttf


BIN
css/font/JetBrainsMono-Regular.woff2


File diff suppressed because it is too large
+ 3 - 0
css/pico.min.css


+ 86 - 0
css/splash.css

@@ -0,0 +1,86 @@
+#splash {
+    position: fixed;
+    z-index: 9999;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+    background-color: #101010;
+}
+
+#splash-logo {
+    margin-top: 6em;
+    color: #ffa000;
+    text-align: center;
+}
+
+#splash-version {
+    color: white;
+    text-align: center;
+    margin-left: 40em;
+}
+
+#splash-text {
+    margin-top: 3em;
+}
+
+#splash-text p {
+    margin: 0 auto;
+    font-size: 120%;
+    text-align: center;
+    white-space: nowrap;
+    overflow: hidden;
+    transform: translateY(-50%);
+    color: white;
+}
+
+#splash-loader {
+    margin-top: 2em;
+    text-align: center;
+    font-family: Menlo,Consolas,Monaco,monospace;
+    font-size: 180%;
+    color: #ffa000;
+}
+
+/* --- Responsive --- */
+
+@media (max-width: 1259px) and (min-width: 851px) {
+    #splash-logo {
+        font-size: 75%;
+    }
+}
+
+@media (max-width: 851px) and (min-width: 504px) {
+    #splash-logo {
+        margin-top: 10em;
+        font-size: 50%;
+    }
+}
+
+@media (max-width: 504px) {
+    #splash-logo {
+        margin-top: 28em;
+        font-size: 34%;
+    }
+
+    #splash-text p {
+        margin: 0 auto;
+        font-size: 80%;
+    }
+
+    #splash-loader {
+        font-size: 120%;
+    }
+}
+
+/* --- Animation --- */
+
+.anim-typewriter{
+    animation: typewriter 1.6s steps(44) 250ms 1 normal both,
+               blinkTextCursor 500ms steps(44) infinite normal;
+}
+
+@keyframes typewriter{
+    from{width: 0;}
+    to{width: 24em;}
+}

+ 161 - 0
css/style.css

@@ -0,0 +1,161 @@
+@font-face {
+    font-family: "JetBrain Mono";
+    src: url("font/JetBrainsMono-Regular.woff2") format("woff2");
+}
+
+@font-face {
+    font-family: "Covenant";
+    src: url("font/Halo-Covenant.ttf") format("truetype");
+}
+
+.jb-mono {
+    font-family: "JetBrain Mono",Menlo,Consolas,Monaco,monospace !important;
+}
+
+.covenant {
+    font-family: "Covenant" !important;
+}
+
+.hide {
+    visibility: hidden;
+}
+
+.none {
+    display: none;
+}
+
+/* --- CMD --- */
+
+input.cmd-in {
+    /* Surcharge les modification de Pico */
+    box-shadow: none;
+    border-color: inherit;
+    padding: 0;
+    margin: 0;
+    height: inherit;
+}
+
+#cmd {
+    scrollbar-width: thin;
+    scrollbar-color: #828282 #101010;
+}
+
+
+#cmd {
+    width: 100%;
+    height: 400px;
+    transition: all .15s linear;
+}
+  
+#cmd.fullscreen {
+    z-index: 9998;
+    width: 100%;
+    height: 100%;
+    top: 0 !important;
+    left: 0 !important;
+}
+
+#cmd::-webkit-scrollbar {
+    width: 8px;
+}
+  
+#cmd::-webkit-scrollbar-track {
+    background: #101010;
+}
+  
+#cmd::-webkit-scrollbar-thumb {
+    background-color: #828282;
+    border-radius: 20px;
+    border: 3px solid #828282;
+}
+
+/* --- OS Window --- */
+
+.window {
+    border: 4px solid #f1f1f1;
+    border-top-left-radius: 4px;
+    border-top-right-radius: 4px;
+}
+
+.window-toolbar {
+    padding: 10px;
+    background: #f1f1f1;
+    border-top-left-radius: 4px;
+    border-top-right-radius: 4px;
+    color: #828282
+}
+
+.window-toolbar:after {
+    content: "";
+    display: table;
+    clear: both;
+}
+
+.window-toolbar-left {
+    float: left;
+    width: 10%;
+    font-size: .7em;
+}
+
+.window-toolbar-center {
+    float: left;
+    width: 75%;
+    text-align: center;
+}
+
+.window-toolbar-right {
+    float: left;
+    width: 15%;
+    text-align: right;
+}
+
+.window-dot {
+    margin-top: 4px;
+    height: 12px;
+    width: 12px;
+    background-color: #bbb;
+    border-radius: 50%;
+    display: inline-block;
+    cursor: pointer;
+}
+
+#close-fs {
+    position: absolute;
+    top: 1em;
+    right: 1em;
+    z-index: 9999;
+    background: #FDD800;
+    color: black;
+    font-weight: bold;
+    border-radius: 80em;
+    height: 2.5em;
+    width: 2.5em;
+    padding: 0.5em;
+}
+
+/* --- Pico 8 --- */
+
+#pico {
+    position: relative;
+    overflow: hidden;
+    height: 68vh;
+    width: 100%;
+    transition: all .15s linear;
+}
+
+#pico iframe {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    border: 0;
+}
+
+#pico.fullscreen {
+    z-index: 9998;
+    width: 100%;
+    height: 100%;
+    top: 0 !important;
+    left: 0 !important;
+}

BIN
favicon.ico


+ 88 - 0
index.php

@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title></title>
+
+    <link rel="stylesheet" type="text/css" href="css/pico.min.css">
+    <link rel="stylesheet" type="text/css" href="css/style.css">
+    <link rel="stylesheet" type="text/css" href="css/cmd.min.css">
+
+    <script src="js/jquery.min.js"></script>
+</head>
+<body>
+
+    <?= file_get_contents('src/splash.html') ?>
+    <h1>Hello</h1>
+
+    <div class="container">
+    <div class="window">
+        <span id="close-fs" role="button" class="hide" onclick="fullscreen()">X</span>
+        <div class="window-toolbar">
+            <div class="window-toolbar-left">
+                <span id="konami-helper">&uarr;&uarr;&darr;&darr;&larr;&rarr;&larr;&rarr;BA</span>
+            </div>
+            <div class="window-toolbar-center">
+                Loquicom terminal
+            </div>
+            <div class="window-toolbar-right">
+                <span class="window-dot" onclick="show()" style="background:#5AC05A;"></span>
+                  <span class="window-dot" onclick="fullscreen()" style="background:#FDD800;"></span>
+                  <span class="window-dot" onclick="remove()" style="background:#ED594A;"></span>
+            </div>
+        </div>
+        <div id="cmd">
+        </div>
+        <div id="pico" class="none">
+            <iframe src="./src/pico8.html" title="Pico 8 game"></iframe>
+        </div>
+    </div>
+    </div>
+    
+    
+
+    <script src="js/cmd.js"></script>
+    <script src="js/konami.js"></script>
+    <script src="js/loaded.js"></script>
+    <script type="text/javascript">
+        
+
+        //fullscreen();
+
+        function fullscreen() {
+            const pos = $('#' + windowMode).position();
+            if (!$('#' + windowMode).hasClass('fullscreen')) {
+                $('#' + windowMode).css('top', Math.trunc(pos.top) + 'px');
+                $('#' + windowMode).css('left', Math.trunc(pos.left) + 'px');
+                $('#' + windowMode).css('position', 'fixed');
+            } else {
+                $('#' + windowMode).one('transitionend', function() {
+                    $('#' + windowMode).css('top', '');
+                    $('#' + windowMode).css('left', '');
+                    $('#' + windowMode).css('position', '');
+                });
+            }
+            
+            $('#' + windowMode).toggleClass('fullscreen');
+            $('#close-fs').toggleClass('hide');
+        }
+
+        function show() {
+            if ($('#' + windowMode).hasClass('pasla')) {
+                $('#' + windowMode).css('height', '');
+            } else {
+                $('#' + windowMode).css('height', '0');
+            }
+            $('#' + windowMode).toggleClass('pasla');
+        }
+
+        function remove() {
+            $('#' + windowMode).css('height', '0');
+            setTimeout(() => {
+                $('.window').remove();
+            }, 148);
+        }
+    </script>
+</body>
+</html>

+ 891 - 0
js/cmd.js

@@ -0,0 +1,891 @@
+ 
+if (!Array.prototype.filter) {
+    Array.prototype.filter = function(fun/*, thisArg*/) {
+      'use strict';
+  
+      if (this === void 0 || this === null) {
+        throw new TypeError();
+      }
+  
+      var t = Object(this);
+      var len = t.length >>> 0;
+      if (typeof fun !== 'function') {
+        throw new TypeError();
+      }
+  
+      var res = [];
+      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
+      for (var i = 0; i < len; i++) {
+        if (i in t) {
+          var val = t[i];
+  
+          // NOTE: Technically this should Object.defineProperty at
+          //       the next index, as push can be affected by
+          //       properties on Object.prototype and Array.prototype.
+          //       But that method's new, and collisions should be
+          //       rare, so use the more-compatible alternative.
+          if (fun.call(thisArg, val, i, t)) {
+            res.push(val);
+          }
+        }
+      }
+  
+      return res;
+    };
+  }
+  
+  if (!String.prototype.startsWith) {
+    String.prototype.startsWith = function(searchString, position) {
+      position = position || 0;
+      return this.indexOf(searchString, position) === position;
+    };
+  }
+  
+  
+  /**
+   * Stack for holding previous commands for retrieval with the up arrow. 
+   * Stores data in localStorage. Won't push consecutive duplicates.
+   *
+   * @author   Jake Gully, chimpytk@gmail.com
+   * @license  MIT License
+   */
+  
+  /**
+   * Constructor
+   * @param {string}  id       Unique id for this stack
+   * @param {integer} max_size Number of commands to store
+   */
+  function CmdStack(id, max_size) {
+    "use strict";
+  
+    var instance_id = id,
+        cur = 0,
+        arr = []; // This is a fairly meaningless name but
+                  // makes it sound like this function was
+                  // written by a pirate.  I'm keeping it.
+  
+    if (typeof id !== 'string') {
+      throw 'Stack error: id should be a string.';
+    }
+  
+    if (typeof max_size !== 'number') {
+      throw 'Stack error: max_size should be a number.';
+    }
+  
+  
+    /**
+     * Store the array in localstorage
+     */
+    function setArray(arr) {
+      localStorage['cmd_stack_' + instance_id] = JSON.stringify(arr);
+    }
+  
+    /**
+     * Load array from localstorage
+     */
+    function getArray() {
+      if (!localStorage['cmd_stack_' + instance_id]) {
+        arr = [];
+        setArray(arr);
+      }
+  
+      try {
+        arr = JSON.parse(localStorage['cmd_stack_' + instance_id]);
+      } catch (err) {
+        return [];
+      }
+      return arr;
+    }
+  
+    /**
+     * Push a command to the array
+     * @param  {string} cmd Command to append to stack
+     */
+    function push(cmd) {
+      arr = getArray();
+      
+      // don't push if same as last command
+      if (cmd === arr[arr.length - 1]) {
+        return false;
+      }
+  
+      arr.push(cmd);
+  
+      // crop off excess
+      while (arr.length > max_size) {
+        arr.shift();
+      }
+  
+      cur = arr.length;
+      setArray(arr);
+    }
+  
+    /**
+     * Get previous command from stack (up key)
+     * @return {string} Retrieved command string
+     */
+    function prev() {
+      cur -= 1;
+  
+      if (cur < 0) {
+        cur = 0;
+      }
+  
+      return arr[cur];
+    }
+  
+    /**
+     * Get next command from stack (down key)
+     * @return {string} Retrieved command string
+     */
+    function next() {
+      cur = cur + 1;
+  
+      // Return a blank string as last item
+      if (cur === arr.length) {
+        return "";
+      }
+  
+      // Limit
+      if (cur > (arr.length - 1)) {
+        cur = (arr.length - 1);
+      }
+  
+      return arr[cur];
+    }
+  
+    /**
+     * Move cursor to last element
+     */
+    function reset() {
+      arr = getArray();
+      cur = arr.length;
+    }
+  
+    /**
+     * Is stack empty
+     * @return {Boolean} True if stack is empty
+     */
+    function isEmpty() {
+      arr = getArray();
+      return (arr.length === 0);
+    }
+    
+    /**
+     * Empty array and remove from localstorage
+     */
+    function empty() {
+      arr = undefined;
+      localStorage.clear();
+      reset();
+    }
+  
+    /**
+     * Get current cursor location
+     * @return {integer} Current cursor index
+     */
+    function getCur() {
+      return cur;
+    }
+  
+    /**
+     * Get entire stack array
+     * @return {array} The stack array
+     */
+    function getArr() {
+      return arr;
+    }
+  
+    /**
+     * Get size of the stack
+     * @return {Integer} Size of stack
+     */
+    function getSize(){
+      return arr.size;
+    }
+  
+    return {
+      push: push,
+      prev: prev,
+      next: next,
+      reset: reset,
+      isEmpty: isEmpty,
+      empty: empty,
+      getCur: getCur,
+      getArr: getArr,
+      getSize: getSize
+    };
+  }
+  
+  
+  /**
+   * HTML5 Command Line Terminal
+   *
+   * @author   Jake Gully (chimpytk@gmail.com)
+   * @license  MIT License
+   */
+  
+  (function (root, factory) {
+    if ( typeof define === 'function' && define.amd ) {
+      define(factory);
+    } else if ( typeof exports === 'object' ) {
+      module.exports = factory();
+    } else {
+      root.Cmd = factory();
+    }
+  }(this, function () {
+    "use strict";
+  
+    var Cmd = function (user_config) {
+      this.keys_array    = [9, 13, 38, 40, 27],
+      this.style         = 'dark',
+      this.popup         = false,
+      this.prompt_str    = '$ ',
+      this.speech_synth_support = ('speechSynthesis' in window && typeof SpeechSynthesisUtterance !== 'undefined'),
+      this.options       = {
+        busy_text:           'Communicating...',
+        external_processor:  function() {},
+        filedrop_enabled:    false,
+        file_upload_url:     'ajax/uploadfile.php',
+        history_id:          'cmd_history',
+        remote_cmd_list_url: '',
+        selector:            '#cmd',
+        tabcomplete_url:     '',
+        talk:                false,
+        unknown_cmd:         'Unrecognised command',
+        typewriter_time:     32
+      },
+      this.voices = false;
+      this.remote_commands = [];
+      this.all_commands = [];
+      this.local_commands = [
+        'clear',
+        'clr',
+        'cls',
+        'clearhistory',
+        'invert',
+        'shh',
+        'talk'
+      ];
+      this.autocompletion_attempted = false;
+  
+      $.extend(this.options, user_config);
+  
+      if (this.options.remote_cmd_list_url) {
+        $.ajax({
+          url: this.options.remote_cmd_list_url,
+          context: this,
+          dataType: 'json',
+          method: 'GET',
+          success: function (data) {
+            this.remote_commands = data;
+            this.all_commands = $.merge(this.remote_commands, this.local_commands)
+          }
+        });
+      } else {
+        this.all_commands = this.local_commands;
+      }
+  
+      if (!$(this.options.selector).length) {
+        throw 'Cmd err: Invalid selector.';
+      }
+  
+      this.cmd_stack = new CmdStack(this.options.history_id, 30);
+  
+      if (this.cmd_stack.isEmpty()) {
+        this.cmd_stack.push('secretmagicword!');
+      }
+  
+      this.cmd_stack.reset();
+      this.setupDOM();
+      this.input.focus();
+    }
+  
+    // ====== Layout / IO / Alter Interface =========
+  
+    /**
+     * Create DOM elements, add click & key handlers
+     */
+    Cmd.prototype.setupDOM = function() {
+      this.wrapper = $(this.options.selector).addClass('cmd-interface');
+  
+      this.container = $('<div/>')
+      .addClass('cmd-container')
+      .appendTo(this.wrapper);
+  
+      if (this.options.filedrop_enabled) {
+        setupFiledrop(); // adds dropzone div
+      }
+  
+      this.clearScreen(); // adds output, input and prompt
+  
+      $(this.options.selector).on('click', $.proxy(this.focusOnInput, this));
+      $(window).resize($.proxy(this.resizeInput, this));
+  
+      this.wrapper.keydown($.proxy(this.handleKeyDown, this));
+      this.wrapper.keyup($.proxy(this.handleKeyUp, this));
+      this.wrapper.keydown($.proxy(this.handleKeyPress, this));
+    }
+  
+    /**
+     * Changes the input type
+     */
+    Cmd.prototype.showInputType = function(input_type) {
+      switch (input_type) {
+        case 'password':
+          this.input = $('<input/>')
+            .attr('type', 'password')
+            .attr('maxlength', 512)
+            .addClass('cmd-in');
+          break;
+        case 'textarea':
+          this.input = $('<textarea/>')
+            .addClass('cmd-in')
+          break;
+        default:
+          this.input = $('<input/>')
+            .attr('type', 'text')
+            .attr('maxlength', 512)
+            .addClass('cmd-in');
+      }
+  
+      this.container.children('.cmd-in').remove();
+  
+      this.input.appendTo(this.container)
+        .attr('title', 'Chimpcom input');
+  
+      this.focusOnInput();
+    }
+  
+    /**
+     * Takes the client's input and the server's output
+     * and displays them appropriately.
+     *
+     * @param   string  cmd_in      The command as entered by the user
+     * @param   string  cmd_out     The server output to write to screen
+     */
+    Cmd.prototype.displayOutput = function(cmd_out) {
+      if (typeof cmd_out !== 'string') {
+        cmd_out = 'Error: invalid cmd_out returned.';
+      }
+  
+      if (this.output.html())  {
+        this.output.append('<br>');
+      }
+  
+      this.output.append(cmd_out + '<br>');
+  
+      if (this.options.talk) {
+        this.speakOutput(cmd_out);
+      }
+  
+      this.cmd_stack.reset();
+  
+      this.input.val('').removeAttr('disabled');
+  
+      this.enableInput();
+      this.focusOnInput();
+      this.activateAutofills();
+    }
+  
+    /**
+     * Take an input string and output it to the screen
+     */
+    Cmd.prototype.displayInput = function(cmd_in) {
+      cmd_in = cmd_in.replace(/&/g, "&amp;")
+        .replace(/</g, "&lt;")
+        .replace(/>/g, "&gt;")
+        .replace(/"/g, "&quot;")
+        .replace(/'/g, "&#039;");
+  
+      this.output.append('<span class="prompt">' + this.prompt_str + '</span> ' +
+        '<span class="grey_text">' + cmd_in + '</span>');
+    }
+  
+    /**
+     * Set the prompt string
+     * @param {string} new_prompt The new prompt string
+     */
+    Cmd.prototype.setPrompt = function(new_prompt) {
+      if (typeof new_prompt !== 'string') {
+        throw 'Cmd error: invalid prompt string.';
+      }
+  
+      this.prompt_str = new_prompt;
+      this.prompt_elem.html(this.prompt_str);
+    }
+  
+    /**
+     * Post-file-drop dropzone reset
+     */
+    Cmd.prototype.resetDropzone = function() {
+      dropzone.css('display', 'none');
+    }
+  
+    /**
+     * Add file drop handlers
+     */
+    Cmd.prototype.setupFiledrop = function() {
+      this.dropzone = $('<div/>')
+      .addClass('dropzone')
+      .appendTo(wrapper)
+      .filedrop({
+        url: this.options.file_upload_url,
+        paramname: 'dropfile', // POST parameter name used on serverside to reference file
+        maxfiles: 10,
+        maxfilesize: 2, // MBs
+        error: function (err, file) {
+          switch (err) {
+          case 'BrowserNotSupported':
+            alert('Your browser does not support html5 drag and drop.');
+            break;
+          case 'TooManyFiles':
+            this.displayInput('[File Upload]');
+            this.displayOutput('Too many files!');
+            this.resetDropzone();
+            break;
+          case 'FileTooLarge':
+            // FileTooLarge also has access to the file which was too large
+            // use file.name to reference the filename of the culprit file
+            this.displayInput('[File Upload]');
+            this.displayOutput('File too big!');
+            this.resetDropzone();
+            break;
+          default:
+            this.displayInput('[File Upload]');
+            this.displayOutput('Fail D:');
+            this.resetDropzone();
+            break;
+          }
+        },
+        dragOver: function () { // user dragging files over #dropzone
+          this.dropzone.css('display', 'block');
+        },
+        dragLeave: function () { // user dragging files out of #dropzone
+          this.resetDropzone();
+        },
+        docOver: function () { // user dragging files anywhere inside the browser document window
+          this.dropzone.css('display', 'block');
+        },
+        docLeave: function () { // user dragging files out of the browser document window
+          this.resetDropzone();
+        },
+        drop: function () { // user drops file
+          this.dropzone.append('<br>File dropped.');
+        },
+        uploadStarted: function (i, file, len) {
+          this.dropzone.append('<br>Upload started...');
+          // a file began uploading
+          // i = index => 0, 1, 2, 3, 4 etc
+          // file is the actual file of the index
+          // len = total files user dropped
+        },
+        uploadFinished: function (i, file, response, time) {
+          // response is the data you got back from server in JSON format.
+          if (response.error !== '') {
+            upload_error = response.error;
+          }
+          this.dropzone.append('<br>Upload finished! ' + response.result);
+        },
+        progressUpdated: function (i, file, progress) {
+          // this function is used for large files and updates intermittently
+          // progress is the integer value of file being uploaded percentage to completion
+          this.dropzone.append('<br>File uploading...');
+        },
+        speedUpdated: function (i, file, speed) { // speed in kb/s
+          this.dropzone.append('<br>Upload speed: ' + speed);
+        },
+        afterAll: function () {
+          // runs after all files have been uploaded or otherwise dealt with
+          if (upload_error !== '') {
+            this.displayInput('[File Upload]');
+            this.displayOutput('Error: ' + upload_error);
+          } else {
+            this.displayInput('[File Upload]');
+            this.displayOutput('[File Upload]', 'Success!');
+          }
+  
+          upload_error = '';
+  
+          this.dropzone.css('display', 'none');
+          this.resetDropzone();
+        }
+      });
+    }
+  
+    /**
+     * [invert description]
+     * @return {[type]} [description]
+     */
+    Cmd.prototype.invert = function() {
+      this.wrapper.toggleClass('inverted');
+    }
+  
+  
+  
+    // ====== Handlers ==============================
+  
+    /**
+     * Do something
+     */
+    Cmd.prototype.handleInput = function(input_str) {
+      var cmd_array = input_str.split(' ');
+      var shown_input = input_str;
+  
+      if (this.input.attr('type') === 'password') {
+        shown_input = new Array(shown_input.length + 1).join("•");
+      }
+  
+      this.displayInput(shown_input);
+  
+      switch (cmd_array[0]) {
+        case '':
+          this.displayOutput('');
+          break;
+        case 'clear':
+        case 'cls':
+        case 'clr':
+          this.clearScreen();
+          break;
+        case 'clearhistory':
+          this.cmd_stack.empty();
+          this.cmd_stack.reset();
+          this.displayOutput('Command history cleared. ');
+          break;
+        case 'invert':
+          this.invert();
+          this.displayOutput('Shazam.');
+          break;
+        case 'shh':
+          if (this.options.talk) {
+            window.speechSynthesis.cancel();
+            this.options.talk = false;
+            this.displayOutput('Speech stopped. Talk mode is still enabled. Type TALK to disable talk mode.');
+            this.options.talk = true;
+          } else {
+            this.displayOutput('Ok.');
+          }
+          break;
+        case 'talk':
+          if (!this.speech_synth_support) {
+            this.displayOutput('You browser doesn\'t support speech synthesis.');
+            return false;
+          }
+  
+          this.options.talk = !this.options.talk;
+          this.displayOutput((this.options.talk ? 'Talk mode enabled.' : 'Talk mode disabled.'));
+          break;
+        default:
+          if (typeof this.options.external_processor !== 'function') {
+            this.displayOutput(this.options.unknown_cmd);
+            return false;
+          }
+  
+          var result = this.options.external_processor(input_str, this);
+  
+          switch (typeof result) {
+            // If undefined, external handler should
+            // call handleResponse when done
+            case 'boolean':
+              if (!result) {
+                this.displayOutput(this.options.unknown_cmd);
+              }
+              break;
+            // If we get a response object, deal with it directly
+            case 'object':
+              this.handleResponse(result);
+              break;
+            // If we have a string, output it. This shouldn't
+            // really happen but it might be useful
+            case 'string':
+              this.displayOutput(result);
+              break;
+            default:
+              this.displayOutput(this.options.unknown_cmd);
+          }
+      }
+    }
+  
+    /**
+     * Handle JSON responses. Used as callback by external command handler
+     * @param  {object} res Chimpcom command object
+     */
+    Cmd.prototype.handleResponse = function(res) {
+      if (res.redirect !== undefined) {
+        document.location.href = res.redirect;
+      }
+  
+      if (res.openWindow !== undefined) {
+        window.open(res.openWindow, '_blank', res.openWindowSpecs);
+      }
+  
+      if (res.log !== undefined && res.log !== '') {
+        console.log(res.log);
+      }
+  
+      if (res.show_pass === true) {
+        this.showInputType('password');
+      } else {
+        this.showInputType();
+      }
+  
+      this.displayOutput(res.cmd_out);
+  
+      if (res.cmd_fill !== '') {
+        this.wrapper.children('.cmd-container').children('.cmd-in').first().val(res.cmd_fill);
+      }
+    }
+  
+    /**
+     * Handle keypresses
+     */
+    Cmd.prototype.handleKeyPress = function(e) {
+      var keyCode = e.keyCode || e.which,
+        input_str = this.input.val(),
+        autocompletions;
+  
+      if (keyCode === 9) { //tab
+        this.tabComplete(input_str);
+      } else {
+        this.autocompletion_attempted = false;
+        if (this.autocomplete_ajax) {
+          this.autocomplete_ajax.abort();
+        }
+  
+        if (keyCode === 13) { // enter
+          if (this.input.attr('disabled')) {
+            return false;
+          }
+  
+          if (e.ctrlKey) {
+            this.cmd_stack.push(input_str);
+            this.goToURL(input_str);
+          } else {
+            this.disableInput();
+  
+            // push command to stack if using text input, i.e. no passwords
+            if (this.input.get(0).type === 'text') {
+              this.cmd_stack.push(input_str);
+            }
+  
+            this.handleInput(input_str);
+          }
+        } else if (keyCode === 38) { // up arrow
+          if (input_str !== "" && this.cmd_stack.cur === (this.cmd_stack.getSize() - 1)) {
+            this.cmd_stack.push(input_str);
+          }
+  
+          this.input.val(this.cmd_stack.prev());
+        } else if (keyCode === 40) { // down arrow
+          this.input.val(this.cmd_stack.next());
+        } else if (keyCode === 27) { // esc
+          if (this.container.css('opacity') > 0.5) {
+            this.container.animate({'opacity': 0}, 300);
+          } else {
+            this.container.animate({'opacity': 1}, 300);
+          }
+        }
+      }
+    }
+  
+    /**
+     * Prevent default action of special keys
+     */
+    Cmd.prototype.handleKeyUp = function(e) {
+      var key = e.which;
+  
+      if ($.inArray(key, this.keys_array) > -1) {
+        e.preventDefault();
+        return false;
+      }
+  
+      return true;
+    }
+  
+    /**
+     * Prevent default action of special keys
+     */
+    Cmd.prototype.handleKeyDown = function(e) {
+      var key = e.which;
+  
+      if ($.inArray(key, this.keys_array) > -1) {
+        e.preventDefault();
+  
+        return false;
+      }
+      return true;
+    }
+  
+    /**
+     * Complete command names when tab is pressed
+     */
+    Cmd.prototype.tabComplete = function(str) {
+      // If we have a space then offload to external processor
+      if (str.indexOf(' ') !== -1) {
+        if (this.options.tabcomplete_url) {
+          if (this.autocomplete_ajax) {
+            this.autocomplete_ajax.abort();
+          }
+  
+          this.autocomplete_ajax = $.ajax({
+            url: this.options.tabcomplete_url,
+            context: this,
+            dataType: 'json',
+            data: {
+              cmd_in: str
+            },
+            success: function (data) {
+              if (data) {
+                this.input.val(data);
+              }
+            }
+          });
+        }
+        this.autocompletion_attempted = false;
+        return;
+      }
+  
+      var autocompletions = this.all_commands.filter(function (value) {
+        return value.startsWith(str);
+      });
+  
+  
+      if (autocompletions.length === 0) {
+        return false;
+      } else if (autocompletions.length === 1) {
+        this.input.val(autocompletions[0]);
+      } else {
+        if (this.autocompletion_attempted) {
+          this.displayOutput(autocompletions.join(', '));
+          this.autocompletion_attempted = false;
+          this.input.val(str);
+          return;
+        } else {
+          this.autocompletion_attempted = true;
+        }
+      }
+    }
+  
+  
+    // ====== Helpers ===============================
+  
+    /**
+     * Takes a user to a given url. Adds "http://" if necessary.
+     */
+    Cmd.prototype.goToURL = function(url) {
+      if (url.substr(0, 4) !== 'http' && url.substr(0, 2) !== '//') {
+        url = 'http://' + url;
+      }
+  
+      if (popup) {
+        window.open(url, '_blank');
+        window.focus();
+      } else {
+        // break out of iframe - used by chrome plugin
+        if (top.location !== location) {
+          top.location.href = document.location.href;
+        }
+  
+        location.href = url;
+      }
+    }
+  
+    /**
+     * Give focus to the command input and
+     * scroll to the bottom of the page
+     */
+    Cmd.prototype.focusOnInput = function() {
+      var cmd_width;
+  
+      $(this.options.selector).scrollTop($(this.options.selector)[0].scrollHeight);
+  
+      this.input.focus();
+    }
+  
+    /**
+     * Make prompt and input fit on one line
+     */
+    Cmd.prototype.resizeInput = function() {
+      var cmd_width = this.wrapper.width() - this.wrapper.find('.main-prompt').first().width() - 45;
+  
+      this.input.focus().css('width', cmd_width);
+    }
+  
+    /**
+     * Clear the screen
+     */
+    Cmd.prototype.clearScreen = function() {
+      this.container.empty();
+  
+      this.output = $('<div/>')
+        .addClass('cmd-output')
+        .appendTo(this.container);
+  
+      this.prompt_elem = $('<span/>')
+        .addClass('main-prompt')
+        .addClass('prompt')
+        .html(this.prompt_str)
+        .appendTo(this.container);
+  
+      this.input = $('<input/>')
+        .addClass('cmd-in')
+        .attr('type', 'text')
+        .attr('maxlength', 512)
+        .appendTo(this.container);
+  
+      this.showInputType();
+  
+      this.input.val('');
+    }
+  
+    /**
+     * Attach click handlers to 'autofills' - divs which, when clicked,
+     * will insert text into the input
+     */
+    Cmd.prototype.activateAutofills = function() {
+      var input = this.input;
+  
+      this.wrapper
+        .find('[data-type=autofill]')
+        .on('click', function() {
+          input.val($(this).data('autofill'));
+        });
+    }
+  
+    /**
+     * Temporarily disable input while runnign commands
+     */
+    Cmd.prototype.disableInput = function() {
+      this.input
+        .attr('disabled', true)
+        .val(this.options.busy_text);
+    }
+  
+    /**
+     * Reenable input after running disableInput()
+     */
+    Cmd.prototype.enableInput = function() {
+      this.input
+        .removeAttr('disabled')
+        .val('');
+    }
+  
+    /**
+     * Speak output aloud using speech synthesis API
+     *
+     * @param {String} output Text to read
+     */
+    Cmd.prototype.speakOutput = function(output) {
+      var msg = new SpeechSynthesisUtterance();
+  
+      msg.volume = 1; // 0 - 1
+      msg.rate   = 1; // 0.1 - 10
+      msg.pitch  = 2; // 0 - 2
+      msg.lang   = 'fr-FR';
+      msg.text   = output;
+  
+      window.speechSynthesis.speak(msg);
+    }
+  
+    return Cmd;
+  }));

File diff suppressed because it is too large
+ 1 - 0
js/jquery.min.js


+ 151 - 0
js/konami.js

@@ -0,0 +1,151 @@
+/*
+ * Konami-JS ~
+ * :: Now with support for touch events and multiple instances for
+ * :: those situations that call for multiple easter eggs!
+ * Code: https://github.com/georgemandis/konami-js
+ * Copyright (c) 2009 George Mandis (https://george.mand.is)
+ * Version: 1.6.3 (11/11/2021)
+ * Licensed under the MIT License (http://opensource.org/licenses/MIT)
+ * Tested in: Safari 4+, Google Chrome 4+, Firefox 3+, IE7+, Mobile Safari 2.2.1+ and Android
+ */
+
+var Konami = function (callback) {
+    var konami = {
+        addEvent: function (obj, type, fn, ref_obj) {
+            if (obj.addEventListener)
+                obj.addEventListener(type, fn, false);
+            else if (obj.attachEvent) {
+                // IE
+                obj["e" + type + fn] = fn;
+                obj[type + fn] = function () {
+                    obj["e" + type + fn](window.event, ref_obj);
+                }
+                obj.attachEvent("on" + type, obj[type + fn]);
+            }
+        },
+        removeEvent: function (obj, eventName, eventCallback) {
+            if (obj.removeEventListener) {
+                obj.removeEventListener(eventName, eventCallback);
+            } else if (obj.attachEvent) {
+                obj.detachEvent(eventName);
+            }
+        },
+        input: "",
+        pattern: "38384040373937396665",
+        keydownHandler: function (e, ref_obj) {
+            if (ref_obj) {
+                konami = ref_obj;
+            } // IE
+            konami.input += e ? e.keyCode : event.keyCode;
+            if (konami.input.length > konami.pattern.length) {
+                konami.input = konami.input.substr((konami.input.length - konami.pattern.length));
+            }
+            if (konami.input === konami.pattern) {
+                konami.code(konami._currentLink);
+                konami.input = '';
+                e.preventDefault();
+                return false;
+            }
+        },
+        load: function (link) {
+            this._currentLink = link;
+            this.addEvent(document, "keydown", this.keydownHandler, this);
+            this.iphone.load(link);
+        },
+        unload: function () {
+            this.removeEvent(document, 'keydown', this.keydownHandler);
+            this.iphone.unload();
+        },
+        code: function (link) {
+            window.location = link
+        },
+        iphone: {
+            start_x: 0,
+            start_y: 0,
+            stop_x: 0,
+            stop_y: 0,
+            tap: false,
+            capture: false,
+            orig_keys: "",
+            keys: ["UP", "UP", "DOWN", "DOWN", "LEFT", "RIGHT", "LEFT", "RIGHT", "TAP", "TAP"],
+            input: [],
+            code: function (link) {
+                konami.code(link);
+            },
+            touchmoveHandler: function (e) {
+                if (e.touches.length === 1 && konami.iphone.capture === true) {
+                    var touch = e.touches[0];
+                    konami.iphone.stop_x = touch.pageX;
+                    konami.iphone.stop_y = touch.pageY;
+                    konami.iphone.tap = false;
+                    konami.iphone.capture = false;
+                    konami.iphone.check_direction();
+                }
+            },
+            touchendHandler: function () {
+                konami.iphone.input.push(konami.iphone.check_direction());
+
+                if (konami.iphone.input.length > konami.iphone.keys.length) konami.iphone.input.shift();
+
+                if (konami.iphone.input.length === konami.iphone.keys.length) {
+                    var match = true;
+                    for (var i = 0; i < konami.iphone.keys.length; i++) {
+                        if (konami.iphone.input[i] !== konami.iphone.keys[i]) {
+                            match = false;
+                        }
+                    }
+                    if (match) {
+                        konami.iphone.code(konami._currentLink);
+                    }
+                }
+            },
+            touchstartHandler: function (e) {
+                konami.iphone.start_x = e.changedTouches[0].pageX;
+                konami.iphone.start_y = e.changedTouches[0].pageY;
+                konami.iphone.tap = true;
+                konami.iphone.capture = true;
+            },
+            load: function (link) {
+                this.orig_keys = this.keys;
+                konami.addEvent(document, "touchmove", this.touchmoveHandler);
+                konami.addEvent(document, "touchend", this.touchendHandler, false);
+                konami.addEvent(document, "touchstart", this.touchstartHandler);
+            },
+            unload: function () {
+                konami.removeEvent(document, 'touchmove', this.touchmoveHandler);
+                konami.removeEvent(document, 'touchend', this.touchendHandler);
+                konami.removeEvent(document, 'touchstart', this.touchstartHandler);
+            },
+            check_direction: function () {
+                x_magnitude = Math.abs(this.start_x - this.stop_x);
+                y_magnitude = Math.abs(this.start_y - this.stop_y);
+                x = ((this.start_x - this.stop_x) < 0) ? "RIGHT" : "LEFT";
+                y = ((this.start_y - this.stop_y) < 0) ? "DOWN" : "UP";
+                result = (x_magnitude > y_magnitude) ? x : y;
+                result = (this.tap === true) ? "TAP" : result;
+                return result;
+            }
+        }
+    }
+
+    typeof callback === "string" && konami.load(callback);
+    if (typeof callback === "function") {
+        konami.code = callback;
+        konami.load();
+    }
+
+    return konami;
+};
+
+
+if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
+        module.exports = Konami;
+} else {
+        if (typeof define === 'function' && define.amd) {
+                define([], function() {
+                        return Konami;
+                });
+        } else {
+                window.Konami = Konami;
+        }
+}

+ 17 - 0
js/loaded.js

@@ -0,0 +1,17 @@
+let windowMode = 'cmd';
+
+$(() => {
+    const shell = new Cmd({
+        selector: '#cmd',
+        busy_text: 'Traitement...',
+        unknown_cmd: 'Commande non reconnue, tapez "aide" pour avoir la liste des commandes disponibles'
+    });
+
+    /* --- Konami Code --- */
+
+    const easterEgg = new Konami(function() {
+        windowMode = (windowMode == 'cmd') ? 'pico' : 'cmd';
+        $('#cmd').toggleClass('none');
+        $('#pico').toggleClass('none');
+    });
+});

File diff suppressed because it is too large
+ 132 - 0
js/pico8-cart.js


+ 129 - 0
js/script.js

@@ -0,0 +1,129 @@
+function toggleFullScreen(elem) {
+    // ## The below if statement seems to work better ## if ((document.fullScreenElement && document.fullScreenElement !== null) || (document.msfullscreenElement && document.msfullscreenElement !== null) || (!document.mozFullScreen && !document.webkitIsFullScreen)) {
+    if ((document.fullScreenElement !== undefined && document.fullScreenElement === null) || (document.msFullscreenElement !== undefined && document.msFullscreenElement === null) || (document.mozFullScreen !== undefined && !document.mozFullScreen) || (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen)) {
+        if (elem.requestFullScreen) {
+            elem.requestFullScreen();
+        } else if (elem.mozRequestFullScreen) {
+            elem.mozRequestFullScreen();
+        } else if (elem.webkitRequestFullScreen) {
+            elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
+        } else if (elem.msRequestFullscreen) {
+            elem.msRequestFullscreen();
+        }
+        return "on";
+    } else {
+        if (document.cancelFullScreen) {
+            document.cancelFullScreen();
+        } else if (document.mozCancelFullScreen) {
+            document.mozCancelFullScreen();
+        } else if (document.webkitCancelFullScreen) {
+            document.webkitCancelFullScreen();
+        } else if (document.msExitFullscreen) {
+            document.msExitFullscreen();
+        }
+        return 'off';
+    }
+}
+
+function help(hide = false) {
+    let str = 'Liste des commandes disponibles :<br/>';
+    str += '&nbsp;&nbsp;- aide : Affiche ce message d&apos;aide<br/>';
+    str += '&nbsp;&nbsp;- bonjour : Formule de politesse<br/>';
+    str += '&nbsp;&nbsp;- dit &lt;mot&gt;: R&eacute;p&egrave;te le mot<br/>';
+    str += '&nbsp;&nbsp;- ping : Vérifie la connexion au terminal<br/>';
+    str += '&nbsp;&nbsp;- cafard : Peut-&ecirc;tre un bug ?<br/>';
+    str += '&nbsp;&nbsp;- flip : Pour exprimer sa col&egrave;re<br/>';
+    str += '&nbsp;&nbsp;- unflip : Pour nettoyer après la col&egrave;re<br/>';
+    str += '&nbsp;&nbsp;- table : Elle est belle ma table<br/>';
+    str += '&nbsp;&nbsp;- <span class="' + ((hide) ? 'covenant' : '') + '">rate : Ouvre la porte</span><br/>';
+    if (hide) {
+        str += '<br/>Erreur lors de la récupération de certaines commandes';
+    } else {
+        str += '&nbsp;&nbsp;- <span class="' + ((hide) ? 'covenant' : '') + '">mirios : Affiche ce message d&apos;aide (mais sans les erreurs)</span><br/>';
+        str += '&nbsp;&nbsp;- <span class="' + ((hide) ? 'covenant' : '') + '">fullscreen : Active/D&eacute;sactive le mode plein écran</span><br/>';
+        str += '&nbsp;&nbsp;- <span class="' + ((hide) ? 'covenant' : '') + '">loquicom : C&apos;est moi le cr&eacute;ateur</span><br/>';
+    }
+    return str;
+}
+
+let table = true;
+function flip(state) {
+    // Si on flip et qu'il y a la table
+    if (state && table) {
+        table = false;
+        return '(╯°□°)╯︵ ┻━┻';
+    } 
+    // Si on flip sans table
+    else if (state) {
+        return 'La table est d&eacute;j&agrave; &agrave; l&apos;envers T_T';
+    }
+    // Si on ne flip pas et qu'il n'y à pas la table
+    else if (!state && !table) {
+        table = true;
+        return '┬─┬ノ( º _ ºノ)';
+    }
+    // Sinon on ne flip pas et la table est déjà la
+    else {
+        return 'La table est d&eacute;j&agrave; bien &agrave; sa place \\o/';
+    }
+}
+
+function tableStatus() {
+    if (table) {
+        return '┬─┬';
+    } else {
+        return '┻━┻';
+    }
+}
+
+function cmd() {
+    const shell = new Cmd({
+        selector: '#cmd',
+        busy_text: 'Traitement...',
+        unknown_cmd: 'Commande non reconnue, tapez "aide" pour avoir la liste des commandes disponibles',
+        external_processor: processor
+    });
+    shell.setPrompt("[chell@glad.os] ➜ ");
+}
+
+function processor(input, cmd) {
+    input = input.toLowerCase().replaceAll('é', 'e').replaceAll('è', 'e').replaceAll('à', 'a');
+    const argc = input.split(" ");
+    const command = argc.shift();
+    switch (command) {
+        case "aide":
+            return help(true);
+        case "help":
+            return "Commande inconnue voulez-vous dire \"aide\" ?";
+        case "ping":
+            return "pong";
+        case "cafard":
+            return "crick crick";
+        case "dit":
+            return 'Chell&nbsp;:&nbsp;<b>' + argc.join(' ') + '</b>';
+        case "bonjour":
+            return "Bonjour à toi ^_^";
+        case "table":
+            return tableStatus();
+        case "flip":
+            return flip(true);
+        case "unflip":
+            return flip(false);
+        case "mirios":
+            return help(false);
+        case "fullscreen":
+            let res = toggleFullScreen(document.getElementById('cmd'));
+            return "Fullscreen " + res;
+        case "loquicom":
+            return 'Lien vers mon Github : https://github.com/Loquicom';
+        case "rate":
+            new Promise((resolve, reject) => {
+                var audio = new Audio('./success.mp3');
+                audio.play();
+            });
+            return '<div class="ascii">' + $('#lock').html() + '</div><br/>Ouverture !';
+        default:
+            // Commande inconnue
+            return false;
+    }
+}

+ 72 - 0
js/splash.js

@@ -0,0 +1,72 @@
+$(() => {
+    const skip = localStorage.getItem('skip-splash');
+    if (skip && skip == 'true') {
+        setTimeout(() => {
+            $('#splash').addClass('none');
+        }, 200);
+    } else {
+        $('#splash-logo').removeClass('hide');
+
+        const loaderInterval = loader();
+        setTimeout(() => {
+            $('#splash-loader').removeClass('hide');
+        }, 200);
+            
+        $('#splash-line-1').removeClass('hide').addClass('anim-typewriter');
+        $('#splash-line-1').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function() {
+            $('#splash-line-2').removeClass('hide').addClass('anim-typewriter');
+        });
+        $('#splash-line-2').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function() {
+            $('#splash-line-3').removeClass('hide').addClass('anim-typewriter');
+        });
+        $('#splash-line-3').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function() {
+            clearInterval(loaderInterval);
+            $('#splash').addClass('none');
+        });
+    }
+});
+
+const spinner = {
+    interval:80,
+    frames:[
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[===&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[====&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[=====&nbsp;&nbsp;&nbsp;]",
+        "[&nbsp;=====&nbsp;&nbsp;]",
+        "[&nbsp;&nbsp;=====&nbsp;]",
+        "[&nbsp;&nbsp;&nbsp;=====]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;====]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;===]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;==]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;==]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;===]",
+        "[&nbsp;&nbsp;&nbsp;&nbsp;====]",
+        "[&nbsp;&nbsp;&nbsp;=====]",
+        "[&nbsp;&nbsp;=====&nbsp;]",
+        "[&nbsp;=====&nbsp;&nbsp;]",
+        "[=====&nbsp;&nbsp;&nbsp;]",
+        "[====&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[===&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]",
+        "[=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]"]
+}
+
+function loader() {
+    const grid = document.getElementById('splash-loader')
+    const spin = document.createElement('div');
+    spin.innerText = spinner.frames[0];
+    grid.appendChild(spin);
+    let i = 0;
+    return setInterval(() => {
+        requestAnimationFrame(() => {
+            spin.innerHTML = spinner.frames[++i % spinner.frames.length];  
+        });
+    }, spinner.interval);
+}
+

+ 164 - 0
proto.html

@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title></title>
+
+    <link rel="stylesheet" type="text/css" href="css/cmd.min.css">
+</head>
+<body>
+    <style type="text/css">
+        body {
+            background: orange;
+        }
+
+        #cmd {
+  width: 100%;
+  height: 400px;
+  transition: all .15s linear;
+        }
+
+        #cmd.fullscreen {
+          z-index: 9998;
+          width: 100%;
+          height: 100%;
+          top: 0 !important;
+          left: 0 !important;
+        }
+
+        #loader {
+            position: fixed;
+            z-index: 9999;
+          width: 100%;
+          height: 100%;
+          top: 0 !important;
+          left: 0 !important;
+          background: blue;
+        }
+
+
+        .window {
+            border: 4px solid #f1f1f1;
+            border-top-left-radius: 4px;
+            border-top-right-radius: 4px;
+        }
+
+        .window-toolbar {
+              padding: 10px;
+              background: #f1f1f1;
+              border-top-left-radius: 4px;
+              border-top-right-radius: 4px;
+        }
+
+                /* Clear floats after the columns */
+        .window-toolbar:after {
+          content: "";
+          display: table;
+          clear: both;
+        }
+
+        .window-toolbar-left {
+            float: left;
+            width: 10%;
+        }
+
+        .window-toolbar-center {
+            float: left;
+            width: 75%;
+            text-align: center;
+        }
+
+        .window-toolbar-right {
+            float: left;
+            width: 15%;
+            text-align: right;
+        }
+
+        .dot {
+  margin-top: 4px;
+  height: 12px;
+  width: 12px;
+  background-color: #bbb;
+  border-radius: 50%;
+  display: inline-block;
+  cursor: pointer;
+}
+
+
+.hide {
+    display: none;
+}
+    </style>
+
+    <div id="loader"></div>
+    <h1>Hello</h1>
+
+    <div class="window">
+        <div class="window-toolbar">
+            <div class="window-toolbar-left">
+                Cmd
+            </div>
+            <div class="window-toolbar-center">
+                Je suis un titre
+            </div>
+            <div class="window-toolbar-right">
+                <span class="dot" onclick="show()" style="background:#5AC05A;"></span>
+                  <span class="dot" onclick="test()" style="background:#FDD800;"></span>
+                  <span class="dot" onclick="window.close()" style="background:#ED594A;"></span>
+            </div>
+        </div>
+        <div id="cmd">
+            <button onclick="test()">FS</button>
+        </div>
+    </div>
+    
+    
+
+    <script src="js/jquery.min.js"></script>
+    <script src="js/cmd.js"></script>
+    <script type="text/javascript">
+        const shell = new Cmd({
+        selector: '#cmd',
+        busy_text: 'Traitement...',
+        unknown_cmd: 'Commande non reconnue, tapez "aide" pour avoir la liste des commandes disponibles'
+    });
+
+        test();
+        setTimeout(() => {
+            $('#loader').remove();
+        }, 500);
+
+        function test() {
+            const pos = $('#cmd').position();
+            if (!$('#cmd').hasClass('fullscreen')) {
+                $('#cmd').css('top', Math.trunc(pos.top) + 'px');
+                $('#cmd').css('left', Math.trunc(pos.left) + 'px');
+                $('#cmd').css('position', 'fixed');
+            } else {
+                $('#cmd').one('transitionend', function() {
+                    $('#cmd').css('top', '');
+                    $('#cmd').css('left', '');
+                    $('#cmd').css('position', '');
+                });
+            }
+            
+            $('#cmd').toggleClass('fullscreen');
+        }
+
+        function show() {
+            if ($('#cmd').hasClass('pasla')) {
+                //$('#cmd').toggleClass('hide');
+                $('#cmd').css('height', '');
+            } else {
+                $('#cmd').css('height', '0');
+                /*$('#cmd').one('transitionend', () => {
+                    $('#cmd').toggleClass('hide');
+                });*/
+            }
+
+            $('#cmd').toggleClass('pasla');
+        }
+    </script>
+</body>
+</html>

File diff suppressed because it is too large
+ 57 - 0
src/pico8.html


+ 27 - 0
src/splash.html

@@ -0,0 +1,27 @@
+<link rel="stylesheet" type="text/css" href="css/splash.css">
+<div id="splash" class="jb-mono">
+    <div id="splash-logo" class="hide">
+        _____/\\\\\\\\\\\\__/\\\\\\___________________________/\\\______________/\\\\\___________________<br/>
+        &nbsp;___/\\\//////////__\////\\\__________________________\/\\\____________/\\\///\\\_________________<br/>
+        &nbsp;&nbsp;__/\\\________________\/\\\__________________________\/\\\__________/\\\/__\///\\\_______________<br/>
+        &nbsp;&nbsp;&nbsp;_\/\\\____/\\\\\\\____\/\\\_____/\\\\\\\\\___________\/\\\_________/\\\______\//\\\__/\\\\\\\\\\_<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;_\/\\\___\/////\\\____\/\\\____\////////\\\_____/\\\\\\\\\________\/\\\_______\/\\\_\/\\\//////__<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_\/\\\_______\/\\\____\/\\\______/\\\\\\\\\\___/\\\////\\\________\//\\\______/\\\__\/\\\\\\\\\\_<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_\/\\\_______\/\\\____\/\\\_____/\\\/////\\\__\/\\\__\/\\\_________\///\\\__/\\\____\////////\\\_<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_\//\\\\\\\\\\\\/___/\\\\\\\\\_\//\\\\\\\\/\\_\//\\\\\\\/\\__/\\\____\///\\\\\/______/\\\\\\\\\\_<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__\////////////____\/////////___\////////\//___\///////\//__\///_______\/////_______\//////////__<br/>
+        <br/>
+        <div id="splash-version">V-8.2.6</div>
+    </div>
+
+    <div id="splash-text">
+        <p id="splash-line-1" class="hide">&Eacute;tablissement d&apos;une connexion ssh</p>
+        <br/>
+        <p id="splash-line-2" class="hide">S&eacute;curisation de la connexion</p>
+        <br/>
+        <p id="splash-line-3" class="hide">Connexion &eacute;tablie</p>
+    </div>
+
+    <div id="splash-loader" class="hide"></div>
+</div>
+<script src="js/splash.js"></script>

Some files were not shown because too many files changed in this diff