diff --git a/site/app.class.js b/site/app.class.js
index 6b724ee..6e7f201 100644
--- a/site/app.class.js
+++ b/site/app.class.js
@@ -56,13 +56,16 @@ class App
project.files.create_version( './folder-test/depth-test/test-3.js', fs.readFileSync( '../test-folder/folder-2/test-3-diff-4.js', 'utf8' ) )
project.files.create_version( './folder-test/test-1.html', fs.readFileSync( '../test-folder/test-1.html', 'utf8' ) )
project.files.create_version( './folder-test/test-2.php', fs.readFileSync( '../test-folder/test-2.php', 'utf8' ) )
- project.files.create_version( './folder-test/big-one.txt', 'content 4\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline' )
+ project.files.create_version( './folder-test/big-one.txt', 'line\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline' )
+ project.files.create_version( './folder-test/loooooooooooooooooooooooooooooooong-one.txt', 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' )
project.files.create_version( './icons/test.js', 'Test icon' )
project.files.create_version( './icons/test.html', 'Test icon' )
project.files.create_version( './icons/test.sass', 'Test icon' )
project.files.create_version( './icons/test.scss', 'Test icon' )
project.files.create_version( './icons/test.less', 'Test icon' )
+ project.files.create_version( './icons/test.stylus', 'Test icon' )
+ project.files.create_version( './icons/test.styl', 'Test icon' )
project.files.create_version( './icons/test.css', 'Test icon' )
project.files.create_version( './icons/test.php', 'Test icon' )
project.files.create_version( './icons/test.json', 'Test icon' )
diff --git a/site/public/_gulp/gulpfile.js b/site/public/_gulp/gulpfile.js
index 83d5ca4..4d975f8 100644
--- a/site/public/_gulp/gulpfile.js
+++ b/site/public/_gulp/gulpfile.js
@@ -6,6 +6,7 @@ var gulp = require( 'gulp' ),
plumber = require( 'gulp-plumber' ),
gulp_rename = require( 'gulp-rename' ),
gulp_stylus = require( 'gulp-stylus' ),
+ nib = require( 'nib' ),
browser_sync = require( 'browser-sync' ).create();
var path = '../';
@@ -41,6 +42,7 @@ gulp.task( 'stylesheet', function()
.pipe( gulp_sourcemaps.init() )
.pipe( plumber() )
.pipe( gulp_stylus( {
+ use : nib(),
compress: true,
} ) )
.pipe( gulp_sourcemaps.write( '.' ) )
diff --git a/site/public/_gulp/package.json b/site/public/_gulp/package.json
index fa127e8..194c1a6 100644
--- a/site/public/_gulp/package.json
+++ b/site/public/_gulp/package.json
@@ -14,6 +14,7 @@
"gulp-sourcemaps": "^1.6.0",
"gulp-stylus": "^2.5.0",
"gulp-uglify": "^1.1.0",
- "gulp-watch": "^3.0.0"
+ "gulp-watch": "^3.0.0",
+ "nib": "^1.1.2"
}
}
diff --git a/site/public/images/icons/android-chrome-192x192.png b/site/public/images/icons/android-chrome-192x192.png
new file mode 100644
index 0000000..1a38df9
Binary files /dev/null and b/site/public/images/icons/android-chrome-192x192.png differ
diff --git a/site/public/images/icons/apple-touch-icon.png b/site/public/images/icons/apple-touch-icon.png
new file mode 100644
index 0000000..42f395e
Binary files /dev/null and b/site/public/images/icons/apple-touch-icon.png differ
diff --git a/site/public/images/icons/browserconfig.xml b/site/public/images/icons/browserconfig.xml
new file mode 100644
index 0000000..ee9ddab
--- /dev/null
+++ b/site/public/images/icons/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #da532c
+
+
+
diff --git a/site/public/images/icons/favicon-16x16.png b/site/public/images/icons/favicon-16x16.png
new file mode 100644
index 0000000..3889fc4
Binary files /dev/null and b/site/public/images/icons/favicon-16x16.png differ
diff --git a/site/public/images/icons/favicon-32x32.png b/site/public/images/icons/favicon-32x32.png
new file mode 100644
index 0000000..b3fcd74
Binary files /dev/null and b/site/public/images/icons/favicon-32x32.png differ
diff --git a/site/public/images/icons/favicon.ico b/site/public/images/icons/favicon.ico
new file mode 100644
index 0000000..fabd3db
Binary files /dev/null and b/site/public/images/icons/favicon.ico differ
diff --git a/site/public/images/icons/manifest.json b/site/public/images/icons/manifest.json
new file mode 100644
index 0000000..cec8acc
--- /dev/null
+++ b/site/public/images/icons/manifest.json
@@ -0,0 +1,12 @@
+{
+ "name": "Keppler",
+ "icons": [
+ {
+ "src": "\/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/site/public/images/icons/mstile-150x150.png b/site/public/images/icons/mstile-150x150.png
new file mode 100644
index 0000000..f914a12
Binary files /dev/null and b/site/public/images/icons/mstile-150x150.png differ
diff --git a/site/public/images/icons/safari-pinned-tab.svg b/site/public/images/icons/safari-pinned-tab.svg
new file mode 100644
index 0000000..ced4361
--- /dev/null
+++ b/site/public/images/icons/safari-pinned-tab.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/site/public/javascript/models/file_tree.js b/site/public/javascript/models/file_tree.js
new file mode 100644
index 0000000..e1fd527
--- /dev/null
+++ b/site/public/javascript/models/file_tree.js
@@ -0,0 +1,643 @@
+'use strict'
+
+/**
+ * File/Folder tree
+ */
+function FileTree( _options )
+{
+ this._constructor( _options )
+}
+
+/**
+ * Create tree and add ./ folder
+ * @param {Object} _options
+ * @param {Boolean} _options.auto_wash - Should clean empty folder on removes
+ */
+FileTree.prototype._constructor = function( _options = {} )
+{
+ if( typeof _options !== 'object' )
+ {
+ console.warn( 'constructor: _options should be an object' )
+ return false
+ }
+
+ // Options
+ this.auto_wash = typeof _options.auto_wash === 'undefined' ? false : _options.auto_wash
+
+ // Set up
+ this.folders = {}
+
+ // Initial folder
+ this.add_folder( '.', {} )
+};
+
+/**
+ * Clean path
+ * @param {String} _path - Path to clean
+ * @return {String} Cleaned path
+ */
+FileTree.prototype.clean_path = function( _path )
+{
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'clean_path: _path should be a string' )
+ return false
+ }
+
+ // Trim
+ _path = _path.trim()
+
+ // Repeating `/`
+ _path = _path.replace( /\/+/g, '/' )
+
+ // Ending `/`
+ _path = _path.replace( /\/$/, '' )
+
+ // Starting `/`
+ _path = _path.replace( /^\//, '' )
+
+ // Missing starting `./`
+ if( _path !== '.' && _path.search( './' ) !== 0 )
+ _path = './' + _path
+
+ return _path
+};
+
+/**
+ * Add a folder
+ * Can create nested folder in one path
+ * @param {String} _path - Path to the folder (start with `./`)
+ * @param {Object} _data - Properties to add to the folder
+ * @returns {Object} Created folder
+ */
+FileTree.prototype.add_folder = function( _path, _data = {} )
+{
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'add_folder: _path should be a string' )
+ return false
+ }
+ if( typeof _data !== 'object' )
+ {
+ console.warn( 'add_folder: _data should be an object' )
+ return false
+ }
+
+ // Set up
+ var path = this.clean_path( _path ),
+ path_parts = path.split( '/' ),
+ folders = this.folders,
+ folder = null
+
+ // Each path part
+ for( var _part of path_parts )
+ {
+ // Already exist
+ if( typeof folders[ _part ] !== 'undefined' )
+ {
+ folder = folders[ _part ]
+ folders = folder.folders
+ }
+
+ // Folder doesn't exist
+ else
+ {
+ // Create folder
+ folder = {
+ folders: {},
+ files : {},
+ name : _part,
+ data : _data
+ }
+
+ // Save
+ folders[ _part ] = folder
+ folders = folder.folders
+ }
+ }
+
+ // Return
+ return folder
+};
+
+/**
+ * Add a file
+ * Will create folders if needed
+ * @param {String} _path - Path to the folder (start with `./`)
+ * @param {Object} _data - Properties to add to the file
+ * @returns {Object} Created file
+ */
+FileTree.prototype.add_file = function( _path, _data = {} )
+{
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'add_file: _path should be a string' )
+ return false
+ }
+ if( typeof _data !== 'object' )
+ {
+ console.warn( 'add_file: _data should be an object' )
+ return false
+ }
+
+ // Set up
+ var path = this.clean_path( _path ),
+ path_parts = path.split( '/' ),
+ file_part = path_parts.pop()
+
+ // Create folder
+ var folder = this.add_folder( path_parts.join( '/' ) )
+
+ // Create file
+ var file = {
+ name: file_part,
+ data: _data
+ }
+
+ // Save
+ folder.files[ file_part ] = file
+
+ return file
+};
+
+/**
+ * Remove folder
+ * Will delete contained folders and contained files
+ * @param {String} _path - Folder to delete (start with `./`)
+ * @returns {Boolean} Folder deleted or not
+ */
+FileTree.prototype.remove_folder = function( _path )
+{
+ // Recursive emptying
+ function empty_folder( folder )
+ {
+ // Delete folders
+ for( var _folder_key in folder.folders )
+ {
+ var _folder = folder.folders[ _folder_key ]
+
+ empty_folder( _folder )
+
+ delete folder.folders[ _folder_key ]
+
+ // Callback
+ if( typeof _folder.data.on_remove === 'function' )
+ {
+ _folder.data.on_remove.apply( this, [ _folder ] )
+ }
+ }
+
+ // Delete files
+ for( var _file_key in folder.files )
+ {
+ var _file = folder.files[ _file_key ]
+
+ delete folder.files[ _file_key ]
+
+ // Callback
+ if( typeof _file.data.on_remove === 'function' )
+ {
+ _file.data.on_remove.apply( this, [ _file ] )
+ }
+ }
+ }
+
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'remove_folder: _path should be a string' )
+ return false
+ }
+
+ // Set up
+ var path = this.clean_path( _path ),
+ path_parts = path.split( '/' ),
+ folder_part = path_parts.pop(),
+ folders = this.folders,
+ folder = null
+
+ // Each path part
+ for( var _part of path_parts )
+ {
+ // Found
+ if( typeof folders[ _part ] !== 'undefined' )
+ {
+ folder = folders[ _part ]
+ folders = folder.folders
+ }
+
+ // Not found
+ else
+ {
+ folder = null
+ folders = null
+ break
+ }
+ }
+
+ // Found
+ if( folders && folders[ folder_part ] )
+ {
+ var folder = folders[ folder_part ]
+
+ // Delete
+ empty_folder( folder )
+ delete folders[ folder_part ]
+
+ // Callback
+ if( typeof folder.data.on_remove === 'function' )
+ {
+ folder.data.on_remove.apply( this, [ folder ] )
+ }
+
+ // Auto wash
+ if( this.auto_wash )
+ this.remove_empty_folders()
+
+ return true
+ }
+
+ return false
+};
+
+/**
+ * Remove file
+ * Will delete contained folders and contained files
+ * @param {String} _path - File to delete (start with `./`)
+ * @returns {Boolean} File deleted or not
+ */
+FileTree.prototype.remove_file = function( _path )
+{
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'remove_file: _path should be a string' )
+ return false
+ }
+
+ // Set up
+ var path = this.clean_path( _path ),
+ path_parts = path.split( '/' ),
+ file_part = path_parts.pop(),
+ folders = this.folders,
+ folder = null
+
+ // Each path part
+ for( var _part of path_parts )
+ {
+ // Found
+ if( typeof folders[ _part ] !== 'undefined' )
+ {
+ folder = folders[ _part ]
+ folders = folder.folders
+ }
+
+ // Not found
+ else
+ {
+ folder = null
+ folders = null
+ break
+ }
+ }
+
+ // Folder found
+ if( folders && folder )
+ {
+ var file = folder.files[ file_part ]
+
+ if( typeof file !== 'undefined' )
+ {
+ // Delete
+ delete folder.files[ file_part ]
+
+ // Auto wash
+ if( this.auto_wash )
+ this.remove_empty_folders()
+
+ // Callback
+ if( typeof file.data.on_remove === 'function' )
+ {
+ file.data.on_remove.apply( this, [ file ] )
+ }
+
+ return true
+ }
+ }
+
+ return false
+};
+
+/**
+ * Get file
+ * @param {String} _path - Path to file
+ * @returns {Object} File
+ */
+FileTree.prototype.get_file = function( _path )
+{
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'get_file: _path should be a string' )
+ return false
+ }
+
+ // Set up
+ var path = this.clean_path( _path ),
+ path_parts = path.split( '/' ),
+ file_part = path_parts.pop(),
+ folders = this.folders,
+ folder = null
+
+ // Each path part
+ for( var _part of path_parts )
+ {
+ // Found
+ if( typeof folders[ _part ] !== 'undefined' )
+ {
+ folder = folders[ _part ]
+ folders = folder.folders
+ }
+
+ // Not found
+ else
+ {
+ folder = null
+ folders = null
+ break
+ }
+ }
+
+ // Folder found
+ if( folders && folder )
+ {
+ var file = folder.files[ file_part ]
+
+ if( typeof file !== 'undefined' )
+ {
+ return file
+ }
+ }
+
+ return false
+};
+
+/**
+ * Get folder
+ * @param {String} _path - Path to folder
+ * @returns {Object} Folder
+ */
+FileTree.prototype.get_folder = function( _path )
+{
+ // Errors
+ if( typeof _path !== 'string' )
+ {
+ console.warn( 'get_folder: _path should be a string' )
+ return false
+ }
+
+ // Set up
+ var path = this.clean_path( _path ),
+ path_parts = path.split( '/' ),
+ folders = this.folders,
+ folder = null
+
+ // Each path part
+ for( var _part of path_parts )
+ {
+ // Already exist
+ if( typeof folders[ _part ] !== 'undefined' )
+ {
+ folder = folders[ _part ]
+ folders = folder.folders
+ }
+
+ // Folder doesn't exist
+ else
+ {
+ return false
+ }
+ }
+
+ // Return
+ return folder
+};
+
+/**
+ * Browse every folders and remove empty ones
+ * @return {Number} Number of removed folders
+ */
+FileTree.prototype.remove_empty_folders = function()
+{
+ // Set up
+ var removed_count = 0
+
+ // Recursive remove
+ function can_remove_folder( folder )
+ {
+ // Each folder inside current folder
+ for( var _folder_key in folder.folders )
+ {
+ // Try to remove folder
+ var _folder = folder.folders[ _folder_key ],
+ can_remove = can_remove_folder( _folder )
+
+ // Remove folder
+ if( can_remove )
+ {
+ removed_count++
+
+ // Delete
+ delete folder.folders[ _folder_key ]
+
+ // Callback
+ if( typeof _folder.data.on_remove === 'function' )
+ {
+ _folder.data.on_remove.apply( this, [ _folder ] )
+ }
+ }
+ }
+
+ // Can be removed
+ var folder_keys = Object.keys( folder.folders ),
+ files_keys = Object.keys( folder.files )
+
+ if( folder_keys.length === 0 && folder_keys.length === 0 )
+ {
+ return true
+ }
+ else
+ {
+ return false
+ }
+ }
+
+ // Try from ./
+ can_remove_folder( this.folders[ '.' ] )
+
+ return removed_count
+};
+
+/**
+ * Describe the tree in ASCII (├ ─ │ └)
+ * @param {Boolean} _log - Directly log to console
+ * @param {Boolean} _colored - Colored tree (only work well in Chrome)
+ * @return {String} Tree
+ */
+FileTree.prototype.describe = function( _log = false, _colored = false )
+{
+ // Set up
+ var string_tree = '',
+ depth = 0,
+ styles = []
+
+ function add_to_string( value, type = null )
+ {
+ if( _colored )
+ {
+ string_tree += '%c'
+
+ switch( type )
+ {
+ case 'structure':
+ styles.push( 'color:#999;' )
+ break
+
+ case 'folder':
+ styles.push( 'color:#999;' )
+ break
+ case 'file':
+ styles.push( 'color:#333;font-weight:bold;' )
+ break
+
+ default:
+ styles.push( '' )
+ break
+ }
+ }
+
+ string_tree += value
+ }
+
+ // Recursive describe
+ function describe_folder( folder, depth, last = [] )
+ {
+ // Set up
+ var folder_keys = Object.keys( folder.folders ),
+ file_keys = Object.keys( folder.files )
+
+ // Each folders
+ for( var i = 0; i < folder_keys.length; i++ )
+ {
+ // Set up
+ var _folder_key = folder_keys[ i ],
+ _folder = folder.folders[ _folder_key ]
+
+ // Add to tree string
+ add_to_string( '\n' )
+
+ for( var j = 0; j < depth; j++ )
+ {
+ if( j === depth - 1 )
+ {
+ if( i === folder_keys.length - 1 && file_keys.length === 0 )
+ add_to_string( ' └', 'structure' )
+ else
+ add_to_string( ' ├', 'structure' )
+ }
+ else
+ {
+ if( last[ j ] )
+ add_to_string( ' ', 'structure' )
+ else
+ add_to_string( ' │', 'structure' )
+ }
+ }
+
+ add_to_string( '─', 'structure' )
+ add_to_string( _folder.name, 'folder' )
+ add_to_string( '/', 'structure' )
+
+ // Last
+ last.push( i === folder_keys.length - 1 && file_keys.length === 0 )
+
+ // Continue
+ describe_folder( _folder, depth + 1, last )
+ }
+
+ // Each files
+ for( var i = 0; i < file_keys.length; i++ )
+ {
+ // Set up
+ var _file_key = file_keys[ i ],
+ _file = folder.files[ _file_key ]
+
+ // Add to tree string
+ string_tree += '\n'
+
+ for( var j = 0; j < depth; j++ )
+ {
+ if( j === depth - 1 )
+ {
+ if( i === file_keys.length - 1 )
+ add_to_string( ' └', 'structure' )
+ else
+ add_to_string( ' ├', 'structure' )
+ }
+ else
+ {
+ if( last[ j ] )
+ add_to_string( ' ', 'structure' )
+ else
+ add_to_string( ' │', 'structure' )
+ }
+ }
+
+ add_to_string( '─', 'structure' )
+ add_to_string( _file.name, 'file' )
+ }
+ }
+
+ // Describe from ./
+ add_to_string( '.', 'folder' )
+ add_to_string( '/', 'structure' )
+ describe_folder( this.folders[ '.' ], depth + 1 )
+
+ // Log
+ if( _log )
+ {
+ console.log.apply(console, [ string_tree ].concat( styles ) )
+ }
+
+ return string_tree
+};
+
+// /**
+// * Tests
+// */
+// var tree = new FileTree( { auto_wash: false } )
+
+// tree.add_folder( './hey/hoy', { active: false, notifs: 0 } )
+// tree.add_folder( './hey/hoy/toto', { active: false, notifs: 0 } )
+// tree.add_folder( './hey/hoy/tata', { active: false, notifs: 0 } )
+
+// tree.add_file( './test-1.txt', { active: false, notifs: 0 } )
+// tree.add_file( './hey/hoy/test-2.txt', { active: false, notifs: 0 } )
+// tree.add_file( './hey/hoy/test-3.txt', { active: false, notifs: 0 } )
+// tree.add_file( './hey/hoy/tata/test-4.txt', { active: false, notifs: 0 } )
+// tree.add_file( './hey/hoy/toto/test-5.txt', { active: false, notifs: 0 } )
+
+// tree.add_file( './hey/hoy/toto/test-6.txt', { active: false, notifs: 0, on_remove: function( file ){ console.log( 'removed file :', file ); } } )
+// tree.remove_file( './hey/hoy/toto/test-6.txt' )
+
+// tree.add_folder( './pwet', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
+// tree.add_folder( './pwet/uh', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
+// tree.remove_folder( './pwet' )
+
+// tree.remove_file( './hey/hoy/test-2.txt' )
+// tree.remove_folder( './hey' )
+
+// tree.describe( true, true )
diff --git a/site/public/javascript/models/tree.js b/site/public/javascript/models/tree.js
deleted file mode 100644
index 78d87b7..0000000
--- a/site/public/javascript/models/tree.js
+++ /dev/null
@@ -1,641 +0,0 @@
-'use strict'
-
-/**
- * File/Folder tree
- */
-class Tree
-{
- /**
- * Create tree and add ./ folder
- * @param {Object} _options
- * @param {Boolean} _options.auto_wash - Should clean empty folder on removes
- */
- constructor( _options = {} )
- {
- if( typeof _options !== 'object' )
- {
- console.warn( 'constructor: _options should be an object' )
- return false
- }
-
- // Options
- this.auto_wash = typeof _options.auto_wash === 'undefined' ? false : _options.auto_wash
-
- // Set up
- this.folders = {}
-
- // Initial folder
- this.add_folder( '.', {} )
- }
-
- /**
- * Clean path
- * @param {String} _path - Path to clean
- * @return {String} Cleaned path
- */
- clean_path( _path )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'clean_path: _path should be a string' )
- return false
- }
-
- // Trim
- _path = _path.trim()
-
- // Repeating `/`
- _path = _path.replace( /\/+/g, '/' )
-
- // Ending `/`
- _path = _path.replace( /\/$/, '' )
-
- // Starting `/`
- _path = _path.replace( /^\//, '' )
-
- // Missing starting `./`
- if( _path !== '.' && _path.search( './' ) !== 0 )
- _path = './' + _path
-
- return _path
- }
-
- /**
- * Add a folder
- * Can create nested folder in one path
- * @param {String} _path - Path to the folder (start with `./`)
- * @param {Object} _data - Properties to add to the folder
- * @returns {Object} Created folder
- */
- add_folder( _path, _data = {} )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'add_folder: _path should be a string' )
- return false
- }
- if( typeof _data !== 'object' )
- {
- console.warn( 'add_folder: _data should be an object' )
- return false
- }
-
- // Set up
- let path = this.clean_path( _path ),
- path_parts = path.split( '/' ),
- folders = this.folders,
- folder = null
-
- // Each path part
- for( let _part of path_parts )
- {
- // Already exist
- if( typeof folders[ _part ] !== 'undefined' )
- {
- folder = folders[ _part ]
- folders = folder.folders
- }
-
- // Folder doesn't exist
- else
- {
- // Create folder
- folder = {
- folders: {},
- files : {},
- name : _part,
- data : _data
- }
-
- // Save
- folders[ _part ] = folder
- folders = folder.folders
- }
- }
-
- // Return
- return folder
- }
-
- /**
- * Add a file
- * Will create folders if needed
- * @param {String} _path - Path to the folder (start with `./`)
- * @param {Object} _data - Properties to add to the file
- * @returns {Object} Created file
- */
- add_file( _path, _data = {} )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'add_file: _path should be a string' )
- return false
- }
- if( typeof _data !== 'object' )
- {
- console.warn( 'add_file: _data should be an object' )
- return false
- }
-
- // Set up
- let path = this.clean_path( _path ),
- path_parts = path.split( '/' ),
- file_part = path_parts.pop()
-
- // Create folder
- let folder = this.add_folder( path_parts.join( '/' ) )
-
- // Create file
- let file = {
- name: file_part,
- data: _data
- }
-
- // Save
- folder.files[ file_part ] = file
-
- return file
- }
-
- /**
- * Remove folder
- * Will delete contained folders and contained files
- * @param {String} _path - Folder to delete (start with `./`)
- * @returns {Boolean} Folder deleted or not
- */
- remove_folder( _path )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'remove_folder: _path should be a string' )
- return false
- }
-
- // Set up
- let path = this.clean_path( _path ),
- path_parts = path.split( '/' ),
- folder_part = path_parts.pop(),
- folders = this.folders,
- folder = null
-
- // Each path part
- for( let _part of path_parts )
- {
- // Found
- if( typeof folders[ _part ] !== 'undefined' )
- {
- folder = folders[ _part ]
- folders = folder.folders
- }
-
- // Not found
- else
- {
- folder = null
- folders = null
- break
- }
- }
-
- // Found
- if( folders && folders[ folder_part ] )
- {
- // Recursive emptying
- function empty_folder( folder )
- {
- // Delete folders
- for( let _folder_key in folder.folders )
- {
- let _folder = folder.folders[ _folder_key ]
-
- empty_folder( _folder )
-
- delete folder.folders[ _folder_key ]
-
- // Callback
- if( typeof _folder.data.on_remove === 'function' )
- {
- _folder.data.on_remove.apply( this, [ _folder ] )
- }
- }
-
- // Delete files
- for( let _file_key in folder.files )
- {
- let _file = folder.files[ _file_key ]
-
- delete folder.files[ _file_key ]
-
- // Callback
- if( typeof _file.data.on_remove === 'function' )
- {
- _file.data.on_remove.apply( this, [ _file ] )
- }
- }
- }
-
- let folder = folders[ folder_part ]
-
- // Delete
- empty_folder( folder )
- delete folders[ folder_part ]
-
- // Callback
- if( typeof folder.data.on_remove === 'function' )
- {
- folder.data.on_remove.apply( this, [ folder ] )
- }
-
- // Auto wash
- if( this.auto_wash )
- this.remove_empty_folders()
-
- return true
- }
-
- return false
- }
-
- /**
- * Remove file
- * Will delete contained folders and contained files
- * @param {String} _path - File to delete (start with `./`)
- * @returns {Boolean} File deleted or not
- */
- remove_file( _path )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'remove_file: _path should be a string' )
- return false
- }
-
- // Set up
- let path = this.clean_path( _path ),
- path_parts = path.split( '/' ),
- file_part = path_parts.pop(),
- folders = this.folders,
- folder = null
-
- // Each path part
- for( let _part of path_parts )
- {
- // Found
- if( typeof folders[ _part ] !== 'undefined' )
- {
- folder = folders[ _part ]
- folders = folder.folders
- }
-
- // Not found
- else
- {
- folder = null
- folders = null
- break
- }
- }
-
- // Folder found
- if( folders && folder )
- {
- let file = folder.files[ file_part ]
-
- if( typeof file !== 'undefined' )
- {
- // Delete
- delete folder.files[ file_part ]
-
- // Auto wash
- if( this.auto_wash )
- this.remove_empty_folders()
-
- // Callback
- if( typeof file.data.on_remove === 'function' )
- {
- file.data.on_remove.apply( this, [ file ] )
- }
-
- return true
- }
- }
-
- return false
- }
-
- /**
- * Get file
- * @param {String} _path - Path to file
- * @returns {Object} File
- */
- get_file( _path )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'get_file: _path should be a string' )
- return false
- }
-
- // Set up
- let path = this.clean_path( _path ),
- path_parts = path.split( '/' ),
- file_part = path_parts.pop(),
- folders = this.folders,
- folder = null
-
- // Each path part
- for( let _part of path_parts )
- {
- // Found
- if( typeof folders[ _part ] !== 'undefined' )
- {
- folder = folders[ _part ]
- folders = folder.folders
- }
-
- // Not found
- else
- {
- folder = null
- folders = null
- break
- }
- }
-
- // Folder found
- if( folders && folder )
- {
- let file = folder.files[ file_part ]
-
- if( typeof file !== 'undefined' )
- {
- return file
- }
- }
-
- return false
- }
-
- /**
- * Get folder
- * @param {String} _path - Path to folder
- * @returns {Object} Folder
- */
- get_folder( _path )
- {
- // Errors
- if( typeof _path !== 'string' )
- {
- console.warn( 'get_folder: _path should be a string' )
- return false
- }
-
- // Set up
- let path = this.clean_path( _path ),
- path_parts = path.split( '/' ),
- folders = this.folders,
- folder = null
-
- // Each path part
- for( let _part of path_parts )
- {
- // Already exist
- if( typeof folders[ _part ] !== 'undefined' )
- {
- folder = folders[ _part ]
- folders = folder.folders
- }
-
- // Folder doesn't exist
- else
- {
- return false
- }
- }
-
- // Return
- return folder
- }
-
- /**
- * Browse every folders and remove empty ones
- * @return {Number} Number of removed folders
- */
- remove_empty_folders()
- {
- // Set up
- var removed_count = 0
-
- // Recursive remove
- function can_remove_folder( folder )
- {
- // Each folder inside current folder
- for( let _folder_key in folder.folders )
- {
- // Try to remove folder
- let _folder = folder.folders[ _folder_key ],
- can_remove = can_remove_folder( _folder )
-
- // Remove folder
- if( can_remove )
- {
- removed_count++
-
- // Delete
- delete folder.folders[ _folder_key ]
-
- // Callback
- if( typeof _folder.data.on_remove === 'function' )
- {
- _folder.data.on_remove.apply( this, [ _folder ] )
- }
- }
- }
-
- // Can be removed
- let folder_keys = Object.keys( folder.folders ),
- files_keys = Object.keys( folder.files )
-
- if( folder_keys.length === 0 && folder_keys.length === 0 )
- {
- return true
- }
- else
- {
- return false
- }
- }
-
- // Try from ./
- can_remove_folder( this.folders[ '.' ] )
-
- return removed_count
- }
-
- /**
- * Describe the tree in ASCII (├ ─ │ └)
- * @param {Boolean} _log - Directly log to console
- * @param {Boolean} _colored - Colored tree (only work well in Chrome)
- * @return {String} Tree
- */
- describe( _log = false, _colored = false )
- {
- // Set up
- var string_tree = '',
- depth = 0,
- styles = []
-
- function add_to_string( value, type = null )
- {
- if( _colored )
- {
- string_tree += '%c'
-
- switch( type )
- {
- case 'structure':
- styles.push( 'color:#999;' )
- break
-
- case 'folder':
- styles.push( 'color:#999;' )
- break
- case 'file':
- styles.push( 'color:#333;font-weight:bold;' )
- break
-
- default:
- styles.push( '' )
- break
- }
- }
-
- string_tree += value
- }
-
- // Recursive describe
- function describe_folder( folder, depth, last = [] )
- {
- // Set up
- let folder_keys = Object.keys( folder.folders ),
- file_keys = Object.keys( folder.files )
-
- // Each folders
- for( let i = 0; i < folder_keys.length; i++ )
- {
- // Set up
- let _folder_key = folder_keys[ i ],
- _folder = folder.folders[ _folder_key ]
-
- // Add to tree string
- add_to_string( '\n' )
-
- for( let j = 0; j < depth; j++ )
- {
- if( j === depth - 1 )
- {
- if( i === folder_keys.length - 1 && file_keys.length === 0 )
- add_to_string( ' └', 'structure' )
- else
- add_to_string( ' ├', 'structure' )
- }
- else
- {
- if( last[ j ] )
- add_to_string( ' ', 'structure' )
- else
- add_to_string( ' │', 'structure' )
- }
- }
-
- add_to_string( '─', 'structure' )
- add_to_string( _folder.name, 'folder' )
- add_to_string( '/', 'structure' )
-
- // Last
- last.push( i === folder_keys.length - 1 && file_keys.length === 0 )
-
- // Continue
- describe_folder( _folder, depth + 1, last )
- }
-
- // Each files
- for( let i = 0; i < file_keys.length; i++ )
- {
- // Set up
- let _file_key = file_keys[ i ],
- _file = folder.files[ _file_key ]
-
- // Add to tree string
- string_tree += '\n'
-
- for( let j = 0; j < depth; j++ )
- {
- if( j === depth - 1 )
- {
- if( i === file_keys.length - 1 )
- add_to_string( ' └', 'structure' )
- else
- add_to_string( ' ├', 'structure' )
- }
- else
- {
- if( last[ j ] )
- add_to_string( ' ', 'structure' )
- else
- add_to_string( ' │', 'structure' )
- }
- }
-
- add_to_string( '─', 'structure' )
- add_to_string( _file.name, 'file' )
- }
- }
-
- // Describe from ./
- add_to_string( '.', 'folder' )
- add_to_string( '/', 'structure' )
- describe_folder( this.folders[ '.' ], depth + 1 )
-
- // Log
- if( _log )
- {
- console.log.apply(console, [ string_tree ].concat( styles ) )
- }
-
- return string_tree
- }
-}
-
-// /**
-// * Tests
-// */
-// let tree = new Tree( { auto_wash: false } )
-
-// tree.add_folder( './hey/hoy', { active: false, notifs: 0 } )
-// tree.add_folder( './hey/hoy/toto', { active: false, notifs: 0 } )
-// tree.add_folder( './hey/hoy/tata', { active: false, notifs: 0 } )
-
-// tree.add_file( './test-1.txt', { active: false, notifs: 0 } )
-// tree.add_file( './hey/hoy/test-2.txt', { active: false, notifs: 0 } )
-// tree.add_file( './hey/hoy/test-3.txt', { active: false, notifs: 0 } )
-// tree.add_file( './hey/hoy/tata/test-4.txt', { active: false, notifs: 0 } )
-// tree.add_file( './hey/hoy/toto/test-5.txt', { active: false, notifs: 0 } )
-
-// tree.add_file( './hey/hoy/toto/test-6.txt', { active: false, notifs: 0, on_remove: function( file ){ console.log( 'removed file :', file ); } } )
-// tree.remove_file( './hey/hoy/toto/test-6.txt' )
-
-// tree.add_folder( './pwet', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
-// tree.add_folder( './pwet/uh', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
-// tree.remove_folder( './pwet' )
-
-// tree.remove_file( './hey/hoy/test-2.txt' )
-// tree.remove_folder( './hey' )
-
-// tree.describe( true, true )
diff --git a/site/public/javascript/services/project.js b/site/public/javascript/services/project.js
index 6446645..cf67ff1 100644
--- a/site/public/javascript/services/project.js
+++ b/site/public/javascript/services/project.js
@@ -16,6 +16,20 @@ application.factory(
_version.date_formated = _version.moment_date.format( 'LTS' );
_version.time_from_now = _version.moment_date.fromNow();
+ // Project last update date
+ if( _version.moment_date.isAfter( result.last_update_moment_date ) )
+ {
+ result.last_update_moment_date = _version.moment_date;
+ result.last_update_date_formated = _version.date_formated;
+ result.last_update_time_from_now = _version.time_from_now;
+ }
+
+ // Lines
+ _version.lines = [];
+ var length = _version.content.split(/\r\n|\r|\n/).length;
+ for( var i = 1; i < length + 1; i++ )
+ _version.lines.push( i );
+
// Differences
var count = 0,
modified = 0;
@@ -65,6 +79,7 @@ application.factory(
'html' : [ 'html', 'htm' ],
'sass' : [ 'sass', 'scss' ],
'less' : [ 'less' ],
+ 'stylus' : [ 'stylus', 'styl' ],
'css' : [ 'css' ],
'php' : [ 'php' ],
'json' : [ 'json' ],
@@ -105,7 +120,9 @@ application.factory(
var result = {};
result.name = '';
result.files = {};
- result.tree = new Tree( { auto_wash: false } );
+ result.files_count = 0;
+ result.tree = new FileTree( { auto_wash: false } );
+ result.date_formated = '';
result.on_update = null;
result.on_new_version = null;
@@ -134,6 +151,8 @@ application.factory(
result.files[ data.path.full ] = file;
result.tree.add_file( data.path.full, file )
+
+ result.files_count++;
}
// Apply callback
@@ -170,6 +189,8 @@ application.factory(
{
result.tree.remove_file( file.path.full )
+ result.files_count--;
+
delete result.files[ data.path.full ]
// Apply callback
@@ -181,7 +202,18 @@ application.factory(
// Update project event
socket.on( 'update_project', function( data )
{
- result.name = data.name;
+ result.name = data.name;
+ result.files_count = data.files.count;
+
+ // Date
+ result.moment_date = moment( data.date );
+ result.date_formated = result.moment_date.format( 'LTS' );
+ result.time_from_now = result.moment_date.fromNow();
+
+ // Last update date
+ result.last_update_moment_date = moment( data.last_update_date );
+ result.last_update_date_formated = result.last_update_moment_date.format( 'LTS' );
+ result.last_update_time_from_now = result.last_update_moment_date.fromNow();
// Duplicate files
for( var _file_key in data.files.items )
diff --git a/site/public/javascript/services/projects.js b/site/public/javascript/services/projects.js
index 61130cf..1dde972 100644
--- a/site/public/javascript/services/projects.js
+++ b/site/public/javascript/services/projects.js
@@ -13,9 +13,9 @@ application.factory(
_project.time_from_now = _project.moment_date.fromNow();
// Last update date
- _project.moment_date = moment( _project.last_update_date );
- _project.last_update_date_formated = _project.moment_date.format( 'LTS' );
- _project.last_update_time_from_now = _project.moment_date.fromNow();
+ _project.last_update_moment_date = moment( _project.last_update_date );
+ _project.last_update_date_formated = _project.last_update_moment_date.format( 'LTS' );
+ _project.last_update_time_from_now = _project.last_update_moment_date.fromNow();
return _project;
}
@@ -32,6 +32,8 @@ application.factory(
{
result.data = data;
+ console.log(data);
+
for( var _project_key in result.data.all )
{
var project = result.data.all[ _project_key ];
diff --git a/site/public/stylesheet/style.css b/site/public/stylesheet/style.css
index 0061db7..4b06cc2 100644
--- a/site/public/stylesheet/style.css
+++ b/site/public/stylesheet/style.css
@@ -1,2 +1,2 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0;}table th{text-align:left}*,*::before,*::after,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}input,button,textarea,select{color:inherit;font-size:inherit;font-style:inherit;font-family:inherit;-webkit-border-radius:0;border-radius:0;-webkit-padding-start:0;align-items:flex-start;text-index:0;border:none;outline:none;background:none;padding:0;margin:0;width:auto;height:auto;line-height:1em}input[type=text],input[type=reset],input[type=password],input[type=search],input[type=email],input[type=tel],input[type=url],input[type=time],input[type=week],input[type=month],input[type=date],input[type=datetime],input[type=datetime-local],input[type=number],input[type=submit],input[type=color],input[type=file],button,textarea,select{height:1em;-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=color]{width:1em}input::-ms-clear{display:none}details,summary{-webkit-appearance:none;-moz-appearance:none;appearance:none}mark{background:none}hr{height:1px;margin:0;padding:0}u{text-decoration:none}a{color:inherit;outline:none}@font-face{font-family:'Stellar';src:url("../fonts/Stellar-Regular.eot");src:url("../fonts/Stellar-Regular.eot?#iefix") format('embedded-opentype'),url("../fonts/Stellar-Regular.woff2") format('woff2'),url("../fonts/Stellar-Regular.woff") format('woff'),url("../fonts/Stellar-Regular.ttf") format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Ubuntu Mono';src:url("../fonts/UbuntuMono-Regular.eot");src:url("../fonts/UbuntuMono-Regular.eot?#iefix") format('embedded-opentype'),url("../fonts/UbuntuMono-Regular.woff2") format('woff2'),url("../fonts/UbuntuMono-Regular.woff") format('woff'),url("../fonts/UbuntuMono-Regular.ttf") format('truetype');font-weight:normal;font-style:normal}body{font-family:Helvetica,Arial;font-size:12px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}body.projects{background:#323759;color:#fff;}body.projects ::-moz-selection{background:#f1eff9}body.projects ::selection{background:#f1eff9}body.projects .gradient-backgroud{position:absolute;top:0;left:0;width:100%;height:920px;background:linear-gradient(0,#323759,#5e50c3 33%,#c9b2cd)}body.projects p,body.projects ul{font-size:14px;line-height:18px;margin-bottom:1em}body.projects code{font-family:'Ubuntu Mono'}body.projects section.landing{position:relative;margin-bottom:60px;}body.projects section.landing .logo{position:absolute;top:315px;left:50%;}body.projects section.landing .logo .disks .disk{position:absolute;border-radius:50%;background:#fff;transform:translateX(-50%) translateY(-50%);opacity:.2;}body.projects section.landing .logo .disks .disk.index-0{width:100px;height:100px;opacity:.7}body.projects section.landing .logo .disks .disk.index-1{width:200px;height:200px}body.projects section.landing .logo .disks .disk.index-2{width:300px;height:300px}body.projects section.landing .logo .disks .disk.index-3{width:400px;height:400px}body.projects section.landing .logo .disks .disk.index-4{width:500px;height:500px}body.projects section.landing .logo .title{font-size:45px;font-family:'Stellar';}body.projects section.landing .logo .title .letter{position:absolute;top:0;left:0;line-height:8px;}body.projects section.landing .logo .title .letter.index-0{left:90px}body.projects section.landing .logo .title .letter.index-1{left:140px}body.projects section.landing .logo .title .letter.index-2{left:190px}body.projects section.landing .logo .title .letter.index-3{left:240px}body.projects section.landing .logo .title .letter.index-4{left:290px}body.projects section.landing .logo .title .letter.index-5{left:340px}body.projects section.landing .logo .title .letter.index-6{left:390px}body.projects section.landing .punch-line{padding-top:600px;text-align:center;}body.projects section.landing .punch-line .text{text-transform:uppercase;font-size:18px;margin:0 0 8px 0}body.projects section.landing .punch-line .links a.link{display:inline-block;padding:5px 10px;margin:0 5px;background:rgba(255,255,255,0.2);text-decoration:none;transition:background .15s;will-change:transform;}body.projects section.landing .punch-line .links a.link:hover{background:rgba(255,255,255,0.3)}body.projects section.projects{position:relative;width:640px;margin:0 auto 90px auto;}body.projects section.projects .head{height:45px;line-height:45px;background:#333759;text-align:center;font-size:14px}body.projects section.projects .content{width:100%;}body.projects section.projects .content span.no-project{display:block;padding:17px 0;background:#eef0fa;text-align:center;color:#6c6e7c;font-size:16px;font-weight:bold;}body.projects section.projects .content span.no-project .title{opacity:.4}body.projects section.projects .content a.project{display:block;background:#eef0fa;color:#6c6e7c;border-bottom:1px solid #dadada;transition:background .15s;will-change:background;}body.projects section.projects .content a.project .title{display:inline-block;vertical-align:top;width:400px;font-size:16px;font-weight:bold;padding:17px}body.projects section.projects .content a.project .details{display:inline-block;vertical-align:top;width:240px;text-align:right;}body.projects section.projects .content a.project .details .detail{display:inline-block;padding:11px 10px;text-align:right;}body.projects section.projects .content a.project .details .detail .label{font-size:10px;opacity:.5;margin-bottom:2px}body.projects section.projects .content a.project .details .detail .value{font-weight:bold}body.projects section.projects .content a.project:last-child{border-bottom:none}body.projects section.projects .content a.project:hover{background:#f6f7fc}body.projects section.text{position:relative;width:640px;margin:0 auto 90px auto;text-align:center;}body.projects section.text .title{margin-bottom:18px;font-family:'Stellar';font-size:32px}body.projects section.text ul{display:inline-block;text-align:left}body.projects section.text pre{width:400px;margin:0 auto 2em auto;background:#282c47;padding:12px 18px;text-align:left;}body.projects section.text pre span.line:before{display:inline-block;content:'$';padding:0 8px 0 0}body.projects section.text pre .opacity-20{opacity:.2;pointer-events:none}body.project{background:#31344a;color:#fff;}body.project .label{font-size:10px;margin-bottom:2px}body.project header{position:relative;height:80px;overflow:hidden;}body.project header .logo{position:absolute;top:40px;left:-35px;}body.project header .logo .disks .disk{position:absolute;border-radius:50%;background:#fff;transform:translateX(-50%) translateY(-50%);}body.project header .logo .disks .disk.index-0{width:70px;height:70px;background:#fff}body.project header .logo .disks .disk.index-1{width:140px;height:140px;background:#666b99}body.project header .logo .disks .disk.index-2{width:210px;height:210px;background:#555980}body.project header .logo .disks .disk.index-3{width:280px;height:280px;background:#474a6b}body.project header .logo .disks .disk.index-4{width:350px;height:350px;background:#3b3e59}body.project header .logo .title{position:absolute;top:0;left:80px;line-height:4px;font-size:28px;font-family:'Stellar';text-transform:uppercase;letter-spacing:2px;text-decoration:none}body.project aside.aside{position:fixed;top:80px;left:0;bottom:0;width:240px;}body.project aside.aside header.aside-header{position:relative;width:100%;height:115px;padding:12px 20px 0 20px;border-top:1px solid #515771;border-bottom:1px solid #515771;background:rgba(0,0,0,0.2);}body.project aside.aside header.aside-header .name{position:absolute;top:15px;left:20px;font-weight:bold}body.project aside.aside header.aside-header .details{text-align:right;}body.project aside.aside header.aside-header .details .detail{margin-bottom:6px;}body.project aside.aside header.aside-header .details .detail .value{font-weight:bold}body.project aside.aside .aside-tree{position:absolute;top:115px;left:0;width:100%;bottom:110px;overflow-y:scroll;}body.project aside.aside .aside-tree nav.files-tree-nav{position:absolute;top:0;left:0;width:100%;}body.project aside.aside .aside-tree nav.files-tree-nav li{line-height:24px;font-size:12px;cursor:pointer;}body.project aside.aside .aside-tree nav.files-tree-nav li .name{position:relative;display:inline-block;padding-left:20px;padding-right:6px;-webkit-font-smoothing:auto;font-smoothing:auto;}@media only screen and (min-resolution:1.5dppx),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:144dpi){body.project aside.aside .aside-tree nav.files-tree-nav li .name{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}}body.project aside.aside .aside-tree nav.files-tree-nav li .notif{display:inline-block;height:12px;margin:0 2px 0 3px;padding:0 4px;line-height:12px;border-radius:6px;font-size:8px;-webkit-font-smoothing:auto;font-smoothing:auto;}body.project aside.aside .aside-tree nav.files-tree-nav li .notif.new-file{background:#748bd5}body.project aside.aside .aside-tree nav.files-tree-nav li .notif.new-version{background:#ec399e;line-height:13px}body.project aside.aside .aside-tree nav.files-tree-nav li > span{display:block;padding-left:16px}body.project aside.aside .aside-tree nav.files-tree-nav li li > span{padding-left:32px}body.project aside.aside .aside-tree nav.files-tree-nav li li li > span{padding-left:48px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li > span{padding-left:64px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li > span{padding-left:80px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li > span{padding-left:96px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li li > span{padding-left:112px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li li li > span{padding-left:128px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li li li li > span{padding-left:144px}body.project aside.aside .aside-tree nav.files-tree-nav li.active{background:#4d5b8d}body.project aside.aside .aside-tree nav.files-tree-nav i{position:absolute;top:25%;left:0;display:block;width:12px;height:50%;background:center center no-repeat;}body.project aside.aside .aside-tree nav.files-tree-nav i.folder{background-image:url("../svg/folder.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.folder-active{background-image:url("../svg/folder-active.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.js{background-image:url("../svg/js.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.html{background-image:url("../svg/html.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.sass{background-image:url("../svg/sass.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.less{background-image:url("../svg/less.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.css{background-image:url("../svg/css.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.php{background-image:url("../svg/php.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.json{background-image:url("../svg/json.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.jade{background-image:url("../svg/jade.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.pug{background-image:url("../svg/pug.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.md{background-image:url("../svg/md.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.sql{background-image:url("../svg/sql.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.apache{background-image:url("../svg/apache.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.yml{background-image:url("../svg/yml.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.svg{background-image:url("../svg/svg.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.font{background-image:url("../svg/font.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.image{background-image:url("../svg/image.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.video{background-image:url("../svg/video.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.audio{background-image:url("../svg/audio.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.zip{background-image:url("../svg/zip.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.txt{background-image:url("../svg/txt.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.coffee{background-image:url("../svg/coffee.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.git{background-image:url("../svg/git.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.xml{background-image:url("../svg/xml.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.twig{background-image:url("../svg/twig.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.c{background-image:url("../svg/c.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.random{background-image:url("../svg/random.svg")}body.project aside.aside footer.aside-footer{position:absolute;bottom:0;left:0;width:100%;height:110px;padding:15px 20px 0 20px;border-top:1px solid #515771;background:rgba(0,0,0,0.2);}body.project aside.aside footer.aside-footer .button-container{margin-bottom:5px}body.project aside.aside footer.aside-footer .button.switch{display:inline-block;padding:5px 10px 5px 0;text-decoration:none;}body.project aside.aside footer.aside-footer .button.switch .switch-icon{display:inline-block;position:relative;top:2px;width:22px;height:12px;margin:0 10px 0 0;}body.project aside.aside footer.aside-footer .button.switch .switch-icon .bar{position:absolute;top:2px;left:0;width:100%;height:8px;background:#404a78;border-radius:4px;transition:background .15s;will-change:background}body.project aside.aside footer.aside-footer .button.switch .switch-icon .disk{position:absolute;top:0;left:0;background:#4f547d;width:12px;height:12px;border-radius:6px;box-shadow:0 2px 2px rgba(0,0,0,0.2);transition:transform .15s;will-change:transform}body.project aside.aside footer.aside-footer .button.switch.active .switch-icon .bar{background:#5965a0}body.project aside.aside footer.aside-footer .button.switch.active .switch-icon .disk{transform:translateX(10px)}body.project aside.aside footer.aside-footer .button.default{display:inline-block;padding:5px 10px;background:rgba(128,147,232,0.2);text-decoration:none;transition:background .15s;will-change:background;}body.project aside.aside footer.aside-footer .button.default:hover{background:rgba(128,147,232,0.3)}body.project section.main{position:fixed;top:80px;left:240px;right:0;bottom:0;}body.project section.main section.no-file{position:absolute;top:0;left:0;width:100%;height:100%;border-top:1px solid #515771;border-left:1px solid #515771;}body.project section.main section.no-file .text{position:absolute;top:50%;left:0;width:100%;text-align:center;color:#c6c0d8;text-transform:uppercase;font-size:20px;opacity:.2;font-weight:bold}body.project section.main section.file{top:0;left:0;width:100%;height:100%;}body.project section.main section.file header.file-header{position:absolute;top:0;left:200px;right:0;height:30px;line-height:30px;background:#4d5b8d;text-align:center;}body.project section.main section.file header.file-header .content{display:inline-block;}body.project section.main section.file header.file-header .content .path{display:inline-block;margin-right:3px;opacity:.5}body.project section.main section.file header.file-header .content .name{display:inline-block;font-weight:bold}body.project section.main section.file nav.versions-nav{position:absolute;top:0;left:0;width:200px;bottom:0;background:#4d5b8d;overflow-y:scroll;}body.project section.main section.file nav.versions-nav a.version{display:block;position:relative;width:200px;height:55px;}body.project section.main section.file nav.versions-nav a.version .background{display:block;position:absolute;top:5px;right:5px;bottom:0;left:5px;background:#404a73;transition:background .15s;will-change:background}body.project section.main section.file nav.versions-nav a.version .content{position:absolute;top:10px;right:13px;bottom:10px;left:10px;text-align:right;}body.project section.main section.file nav.versions-nav a.version .content .date{font-weight:bold}body.project section.main section.file nav.versions-nav a.version .content .time-from-now{font-size:10px;opacity:.5}body.project section.main section.file nav.versions-nav a.version .content .differences{position:absolute;top:0;left:0;text-align:left;}body.project section.main section.file nav.versions-nav a.version .content .differences .label{margin-bottom:4px}body.project section.main section.file nav.versions-nav a.version .content .differences .bar{display:block;position:relative;width:75px;height:2px;margin-bottom:3px;background:rgba(189,202,255,0.25);transition:background .15s;will-change:background;}body.project section.main section.file nav.versions-nav a.version .content .differences .bar .fill{position:absolute;top:0;left:0;height:100%;background:#17f861}body.project section.main section.file nav.versions-nav a.version .content .differences .percent{font-size:10px;color:#17f861;white-space:nowrap;text-align:right;-webkit-font-smoothing:auto;font-smoothing:auto;}@media only screen and (min-resolution:1.5dppx),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:144dpi){body.project section.main section.file nav.versions-nav a.version .content .differences .percent{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}}body.project section.main section.file nav.versions-nav a.version:hover .background{background:#616d9f}body.project section.main section.file nav.versions-nav a.version:hover .content .differences .bar{background:rgba(189,202,255,0.3)}body.project section.main section.file nav.versions-nav a.version.active .background{background:#7481b5}body.project section.main section.file nav.versions-nav a.version.active .content .differences .bar{background:rgba(189,202,255,0.5)}body.project section.main section.file section.code{position:absolute;top:30px;right:0;bottom:0;left:200px;overflow-y:scroll;}body.project section.main section.file section.code pre{position:relative;overflow:hidden;}body.project section.main section.file section.code pre code{line-height:20px;font-family:monospace;}body.project section.main section.file section.code pre code.lines{position:absolute;top:0;left:0;width:38px;padding:.5em;opacity:.2}body.project section.main section.file section.code pre code.hljs{margin-left:38px;background:none}body.project section.main section.file section.code pre code.differences{position:absolute;top:0;left:38px;padding:.5em;pointer-events:none;}body.project section.main section.file section.code pre code.differences .value{visibility:hidden}body.project section.main section.file section.code pre code.differences.inactive{display:none}body.project section.main section.file section.code pre code.differences span.removed{display:none;border:1px solid #f00;}body.project section.main section.file section.code pre code.differences span.removed .value{display:none}body.project section.main section.file section.code pre code.differences span.added{border:1px solid #b0ea23;background:rgba(176,234,35,0.1)}
+html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0;}table th{text-align:left}*,*::before,*::after,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input,button,textarea,select{color:inherit;font-size:inherit;font-style:inherit;font-family:inherit;-webkit-border-radius:0;border-radius:0;-webkit-padding-start:0;-webkit-box-align:start;-moz-box-align:start;-o-box-align:start;-ms-flex-align:start;-webkit-align-items:flex-start;align-items:flex-start;text-index:0;border:none;outline:none;background:none;padding:0;margin:0;width:auto;height:auto;line-height:1em}input[type=text],input[type=reset],input[type=password],input[type=search],input[type=email],input[type=tel],input[type=url],input[type=time],input[type=week],input[type=month],input[type=date],input[type=datetime],input[type=datetime-local],input[type=number],input[type=submit],input[type=color],input[type=file],button,textarea,select{height:1em;-webkit-appearance:none;-moz-appearance:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=color]{width:1em}input::-ms-clear{display:none}details,summary{-webkit-appearance:none;-moz-appearance:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}mark{background:none}hr{height:1px;margin:0;padding:0}u{text-decoration:none}a{color:inherit;outline:none}@font-face{font-family:'Stellar';src:url("../fonts/Stellar-Regular.eot");src:url("../fonts/Stellar-Regular.eot?#iefix") format('embedded-opentype'),url("../fonts/Stellar-Regular.woff2") format('woff2'),url("../fonts/Stellar-Regular.woff") format('woff'),url("../fonts/Stellar-Regular.ttf") format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'Ubuntu Mono';src:url("../fonts/UbuntuMono-Regular.eot");src:url("../fonts/UbuntuMono-Regular.eot?#iefix") format('embedded-opentype'),url("../fonts/UbuntuMono-Regular.woff2") format('woff2'),url("../fonts/UbuntuMono-Regular.woff") format('woff'),url("../fonts/UbuntuMono-Regular.ttf") format('truetype');font-weight:normal;font-style:normal}body{font-family:Helvetica,Arial;font-size:12px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased;}body ::-moz-selection{background:#f1eff9}body ::selection{background:#f1eff9}body.projects{background:#323759;color:#fff;}body.projects ::-moz-selection{background:#f1eff9}body.projects ::selection{background:#f1eff9}body.projects .gradient-backgroud{position:absolute;top:0;left:0;width:100%;height:920px;background:-webkit-linear-gradient(90deg, #323759, #5e50c3 33%, #c9b2cd);background:-moz-linear-gradient(90deg, #323759, #5e50c3 33%, #c9b2cd);background:-o-linear-gradient(90deg, #323759, #5e50c3 33%, #c9b2cd);background:-ms-linear-gradient(90deg, #323759, #5e50c3 33%, #c9b2cd);background:linear-gradient(0deg, #323759, #5e50c3 33%, #c9b2cd)}body.projects p,body.projects ul{font-size:14px;line-height:18px;margin-bottom:1em}body.projects code{font-family:'Ubuntu Mono'}body.projects section.landing{position:relative;margin-bottom:60px;}body.projects section.landing .logo{position:absolute;top:315px;left:50%;}body.projects section.landing .logo .disks .disk{position:absolute;border-radius:50%;background:#fff;-webkit-transform:translateX(-50%) translateY(-50%);-moz-transform:translateX(-50%) translateY(-50%);-o-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);opacity:.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";filter:alpha(opacity=20);}body.projects section.landing .logo .disks .disk.index-0{width:100px;height:100px;opacity:.7;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";filter:alpha(opacity=70)}body.projects section.landing .logo .disks .disk.index-1{width:200px;height:200px}body.projects section.landing .logo .disks .disk.index-2{width:300px;height:300px}body.projects section.landing .logo .disks .disk.index-3{width:400px;height:400px}body.projects section.landing .logo .disks .disk.index-4{width:500px;height:500px}body.projects section.landing .logo .title{font-size:45px;font-family:'Stellar';}body.projects section.landing .logo .title .letter{position:absolute;top:0;left:0;line-height:8px;}body.projects section.landing .logo .title .letter.index-0{left:90px}body.projects section.landing .logo .title .letter.index-1{left:140px}body.projects section.landing .logo .title .letter.index-2{left:190px}body.projects section.landing .logo .title .letter.index-3{left:240px}body.projects section.landing .logo .title .letter.index-4{left:290px}body.projects section.landing .logo .title .letter.index-5{left:340px}body.projects section.landing .logo .title .letter.index-6{left:390px}body.projects section.landing .punch-line{padding-top:600px;text-align:center;}body.projects section.landing .punch-line .text{text-transform:uppercase;font-size:18px;margin:0 0 8px 0}body.projects section.landing .punch-line .links a.link{display:inline-block;padding:5px 10px;margin:0 5px;background:rgba(255,255,255,0.2);text-decoration:none;-webkit-transition:background 0.15s;-moz-transition:background 0.15s;-o-transition:background 0.15s;-ms-transition:background 0.15s;transition:background 0.15s;will-change:transform;}body.projects section.landing .punch-line .links a.link:hover{background:rgba(255,255,255,0.3)}body.projects section.projects{position:relative;width:640px;margin:0 auto 90px auto;}body.projects section.projects .head{height:45px;line-height:45px;background:#333759;text-align:center;font-size:14px}body.projects section.projects .content{width:100%;}body.projects section.projects .content span.no-project{display:block;padding:17px 0;background:#eef0fa;text-align:center;color:#6c6e7c;font-size:16px;font-weight:bold;}body.projects section.projects .content span.no-project .title{opacity:.4;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";filter:alpha(opacity=40)}body.projects section.projects .content a.project{display:block;background:#eef0fa;color:#6c6e7c;border-bottom:1px solid #dadada;-webkit-transition:background 0.15s;-moz-transition:background 0.15s;-o-transition:background 0.15s;-ms-transition:background 0.15s;transition:background 0.15s;will-change:background;}body.projects section.projects .content a.project .title{display:inline-block;vertical-align:top;width:400px;font-size:16px;font-weight:bold;padding:17px}body.projects section.projects .content a.project .details{display:inline-block;vertical-align:top;width:240px;text-align:right;}body.projects section.projects .content a.project .details .detail{display:inline-block;padding:11px 10px;text-align:right;}body.projects section.projects .content a.project .details .detail .label{font-size:10px;opacity:.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);margin-bottom:2px}body.projects section.projects .content a.project .details .detail .value{font-weight:bold}body.projects section.projects .content a.project:last-child{border-bottom:none}body.projects section.projects .content a.project:hover{background:#f6f7fc}body.projects section.text{position:relative;width:640px;margin:0 auto 90px auto;text-align:center;}body.projects section.text .title{margin-bottom:18px;font-family:'Stellar';font-size:32px}body.projects section.text ul{display:inline-block;text-align:left}body.projects section.text pre{width:400px;margin:0 auto 2em auto;background:#282c47;padding:12px 18px;text-align:left;}body.projects section.text pre span.line:before{display:inline-block;content:'$';padding:0 8px 0 0}body.projects section.text pre .opacity-20{opacity:.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";filter:alpha(opacity=20);pointer-events:none}body.project{background:#31344a;color:#fff;}body.project .label{font-size:10px;margin-bottom:2px}body.project header{position:relative;height:80px;overflow:hidden;}body.project header .logo{position:absolute;top:40px;left:-35px;}body.project header .logo .disks .disk{position:absolute;border-radius:50%;background:#fff;-webkit-transform:translateX(-50%) translateY(-50%);-moz-transform:translateX(-50%) translateY(-50%);-o-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);}body.project header .logo .disks .disk.index-0{width:70px;height:70px;background:#fff}body.project header .logo .disks .disk.index-1{width:140px;height:140px;background:#666b99}body.project header .logo .disks .disk.index-2{width:210px;height:210px;background:#555980}body.project header .logo .disks .disk.index-3{width:280px;height:280px;background:#474a6b}body.project header .logo .disks .disk.index-4{width:350px;height:350px;background:#3b3e59}body.project header .logo .title{position:absolute;top:0;left:80px;line-height:4px;font-size:28px;font-family:'Stellar';text-transform:uppercase;letter-spacing:2px;text-decoration:none}body.project aside.aside{position:fixed;top:80px;left:0;bottom:0;width:240px;}body.project aside.aside header.aside-header{position:relative;width:100%;height:115px;padding:12px 20px 0 20px;border-top:1px solid #515771;border-bottom:1px solid #515771;background:#2c2f42;}body.project aside.aside header.aside-header .name{position:absolute;top:15px;left:20px;font-weight:bold}body.project aside.aside header.aside-header .details{text-align:right;}body.project aside.aside header.aside-header .details .detail{margin-bottom:6px;}body.project aside.aside header.aside-header .details .detail .value{font-weight:bold}body.project aside.aside .aside-tree{position:absolute;top:115px;left:0;bottom:95px;width:calc(100% + 15px);overflow-y:scroll;overflow-x:scroll;}body.project aside.aside .aside-tree nav.files-tree-nav{position:absolute;top:0;left:0;width:100%;}body.project aside.aside .aside-tree nav.files-tree-nav li{line-height:24px;font-size:12px;cursor:pointer;white-space:nowrap;}body.project aside.aside .aside-tree nav.files-tree-nav li .name{position:relative;display:inline-block;padding-left:20px;padding-right:6px;-webkit-font-smoothing:auto;font-smoothing:auto;}@media only screen and (min-resolution:1.5dppx),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:144dpi){body.project aside.aside .aside-tree nav.files-tree-nav li .name{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}}body.project aside.aside .aside-tree nav.files-tree-nav li .notif{display:inline-block;height:12px;margin:0 2px 0 3px;padding:0 4px;line-height:12px;border-radius:6px;font-size:8px;-webkit-font-smoothing:auto;font-smoothing:auto;}body.project aside.aside .aside-tree nav.files-tree-nav li .notif.new-file{background:#748bd5}body.project aside.aside .aside-tree nav.files-tree-nav li .notif.new-version{background:#ec399e;line-height:13px}body.project aside.aside .aside-tree nav.files-tree-nav li > span{display:inline-block;padding-right:20px;padding-left:15px}body.project aside.aside .aside-tree nav.files-tree-nav li li > span{padding-left:30px}body.project aside.aside .aside-tree nav.files-tree-nav li li li > span{padding-left:45px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li > span{padding-left:60px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li > span{padding-left:75px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li > span{padding-left:90px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li li > span{padding-left:105px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li li li > span{padding-left:120px}body.project aside.aside .aside-tree nav.files-tree-nav li li li li li li li li li > span{padding-left:135px}body.project aside.aside .aside-tree nav.files-tree-nav li.active{background:#4d5b8d}body.project aside.aside .aside-tree nav.files-tree-nav i{position:absolute;top:25%;left:0;display:block;width:12px;height:50%;background:center center no-repeat;}body.project aside.aside .aside-tree nav.files-tree-nav i.folder{background-image:url("../svg/folder.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.folder-active{background-image:url("../svg/folder-active.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.js{background-image:url("../svg/js.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.html{background-image:url("../svg/html.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.sass{background-image:url("../svg/sass.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.less{background-image:url("../svg/less.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.stylus{background-image:url("../svg/stylus.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.css{background-image:url("../svg/css.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.php{background-image:url("../svg/php.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.json{background-image:url("../svg/json.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.jade{background-image:url("../svg/jade.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.pug{background-image:url("../svg/pug.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.md{background-image:url("../svg/md.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.sql{background-image:url("../svg/sql.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.apache{background-image:url("../svg/apache.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.yml{background-image:url("../svg/yml.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.svg{background-image:url("../svg/svg.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.font{background-image:url("../svg/font.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.image{background-image:url("../svg/image.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.video{background-image:url("../svg/video.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.audio{background-image:url("../svg/audio.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.zip{background-image:url("../svg/zip.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.txt{background-image:url("../svg/txt.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.coffee{background-image:url("../svg/coffee.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.git{background-image:url("../svg/git.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.xml{background-image:url("../svg/xml.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.twig{background-image:url("../svg/twig.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.c{background-image:url("../svg/c.svg")}body.project aside.aside .aside-tree nav.files-tree-nav i.random{background-image:url("../svg/random.svg")}body.project aside.aside footer.aside-footer{position:absolute;bottom:0;left:0;width:100%;height:110px;padding:10px 20px 0 20px;border-top:1px solid #515771;background:#2c2f42;}body.project aside.aside footer.aside-footer .button-container.switch,body.project aside.aside footer.aside-footer .button.switch{display:inline-block;padding:5px 10px 5px 0;text-decoration:none;}body.project aside.aside footer.aside-footer .button-container.switch .switch-icon,body.project aside.aside footer.aside-footer .button.switch .switch-icon{display:inline-block;position:relative;top:2px;width:22px;height:12px;margin:0 10px 0 0;}body.project aside.aside footer.aside-footer .button-container.switch .switch-icon .bar,body.project aside.aside footer.aside-footer .button.switch .switch-icon .bar{position:absolute;top:2px;left:0;width:100%;height:8px;background:#404a78;border-radius:4px;-webkit-transition:background 0.15s;-moz-transition:background 0.15s;-o-transition:background 0.15s;-ms-transition:background 0.15s;transition:background 0.15s;will-change:background}body.project aside.aside footer.aside-footer .button-container.switch .switch-icon .disk,body.project aside.aside footer.aside-footer .button.switch .switch-icon .disk{position:absolute;top:0;left:0;background:#4f547d;width:12px;height:12px;border-radius:6px;-webkit-box-shadow:0 2px 2px rgba(0,0,0,0.2);box-shadow:0 2px 2px rgba(0,0,0,0.2);-webkit-transition:-webkit-transform 0.15s;-moz-transition:-moz-transform 0.15s;-o-transition:-o-transform 0.15s;-ms-transition:-ms-transform 0.15s;transition:transform 0.15s;will-change:transform}body.project aside.aside footer.aside-footer .button-container.switch.active .switch-icon .bar,body.project aside.aside footer.aside-footer .button.switch.active .switch-icon .bar{background:#5965a0}body.project aside.aside footer.aside-footer .button-container.switch.active .switch-icon .disk,body.project aside.aside footer.aside-footer .button.switch.active .switch-icon .disk{-webkit-transform:translateX(10px);-moz-transform:translateX(10px);-o-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}body.project aside.aside footer.aside-footer .button-container.default,body.project aside.aside footer.aside-footer .button.default{display:inline-block;margin:10px 0;padding:5px 10px;background:rgba(128,147,232,0.2);text-decoration:none;-webkit-transition:background 0.15s;-moz-transition:background 0.15s;-o-transition:background 0.15s;-ms-transition:background 0.15s;transition:background 0.15s;will-change:background;}body.project aside.aside footer.aside-footer .button-container.default:hover,body.project aside.aside footer.aside-footer .button.default:hover{background:rgba(128,147,232,0.3)}body.project section.main{position:fixed;top:80px;left:240px;right:0;bottom:0;background:#31344a;}body.project section.main section.no-file{position:absolute;top:0;left:0;width:100%;height:100%;border-top:1px solid #515771;border-left:1px solid #515771;}body.project section.main section.no-file .text{position:absolute;top:50%;left:0;width:100%;text-align:center;color:#c6c0d8;text-transform:uppercase;font-size:20px;opacity:.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";filter:alpha(opacity=20);font-weight:bold}body.project section.main section.file{top:0;left:0;width:100%;height:100%;}body.project section.main section.file header.file-header{position:absolute;top:0;left:200px;right:0;height:30px;line-height:30px;background:#4d5b8d;text-align:center;}body.project section.main section.file header.file-header .content{display:inline-block;}body.project section.main section.file header.file-header .content .path{display:inline-block;margin-right:3px;opacity:.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50)}body.project section.main section.file header.file-header .content .name{display:inline-block;font-weight:bold}body.project section.main section.file nav.versions-nav{position:absolute;top:0;left:0;bottom:0;width:215px;padding-bottom:5px;background:#4d5b8d;overflow-y:scroll;overflow-x:hidden;}body.project section.main section.file nav.versions-nav a.version{display:block;position:relative;width:200px;height:55px;}body.project section.main section.file nav.versions-nav a.version .background{display:block;position:absolute;top:5px;right:5px;bottom:0;left:5px;background:#404a73;-webkit-transition:background 0.15s;-moz-transition:background 0.15s;-o-transition:background 0.15s;-ms-transition:background 0.15s;transition:background 0.15s;will-change:background}body.project section.main section.file nav.versions-nav a.version .content{position:absolute;top:10px;right:13px;bottom:10px;left:10px;text-align:right;}body.project section.main section.file nav.versions-nav a.version .content .date{font-weight:bold}body.project section.main section.file nav.versions-nav a.version .content .time-from-now{font-size:10px;opacity:.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50)}body.project section.main section.file nav.versions-nav a.version .content .differences{position:absolute;top:0;left:0;text-align:left;}body.project section.main section.file nav.versions-nav a.version .content .differences .label{margin-bottom:4px}body.project section.main section.file nav.versions-nav a.version .content .differences .bar{display:block;position:relative;width:75px;height:2px;margin-bottom:3px;background:rgba(189,202,255,0.25);-webkit-transition:background 0.15s;-moz-transition:background 0.15s;-o-transition:background 0.15s;-ms-transition:background 0.15s;transition:background 0.15s;will-change:background;}body.project section.main section.file nav.versions-nav a.version .content .differences .bar .fill{position:absolute;top:0;left:0;height:100%;background:#17f861}body.project section.main section.file nav.versions-nav a.version .content .differences .percent{font-size:10px;color:#17f861;white-space:nowrap;text-align:right;-webkit-font-smoothing:auto;font-smoothing:auto;}@media only screen and (min-resolution:1.5dppx),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:144dpi){body.project section.main section.file nav.versions-nav a.version .content .differences .percent{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}}body.project section.main section.file nav.versions-nav a.version:hover .background{background:#616d9f}body.project section.main section.file nav.versions-nav a.version:hover .content .differences .bar{background:rgba(189,202,255,0.3)}body.project section.main section.file nav.versions-nav a.version.active .background{background:#7481b5}body.project section.main section.file nav.versions-nav a.version.active .content .differences .bar{background:rgba(189,202,255,0.5)}body.project section.main section.file section.code{position:absolute;top:30px;right:-15px;bottom:-15px;left:200px;background:#31344a;overflow-y:scroll;overflow-x:scroll;}body.project section.main section.file section.code pre{position:relative;}body.project section.main section.file section.code pre code{line-height:20px;font-family:monospace}body.project section.main section.file section.code .lines{position:absolute;top:0;left:0;width:38px;padding:.5em;opacity:.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";filter:alpha(opacity=20)}body.project section.main section.file section.code .current pre code{display:inline-block;margin-right:15px;margin-bottom:15px;margin-left:38px;background:none}body.project section.main section.file section.code .differences{position:absolute;top:0;left:38px;padding:.5em;pointer-events:none;}body.project section.main section.file section.code .differences pre code .value{visibility:hidden}body.project section.main section.file section.code .differences pre code.inactive{display:none}body.project section.main section.file section.code .differences pre code span.removed{display:none;border:1px solid #f00;}body.project section.main section.file section.code .differences pre code span.removed .value{display:none}body.project section.main section.file section.code .differences pre code span.added{border:1px solid #b0ea23;background:rgba(176,234,35,0.1)}
/*# sourceMappingURL=style.css.map */
diff --git a/site/public/stylus/base/general.styl b/site/public/stylus/base/general.styl
index 6587ed7..d28793d 100644
--- a/site/public/stylus/base/general.styl
+++ b/site/public/stylus/base/general.styl
@@ -3,6 +3,12 @@ body
font-size 12px
font-smoothing(antialiased)
+ ::-moz-selection
+ background #f1eff9
+ ::selection
+ background #f1eff9
+
+
diff --git a/site/public/stylus/pages/project.styl b/site/public/stylus/pages/project.styl
index 468d048..d76b221 100644
--- a/site/public/stylus/pages/project.styl
+++ b/site/public/stylus/pages/project.styl
@@ -68,7 +68,7 @@ body.project
padding 12px 20px 0 20px
border-top 1px solid #515771
border-bottom 1px solid #515771
- background rgba(0,0,0,0.2)
+ background #2c2f42
.name
position absolute
@@ -90,9 +90,10 @@ body.project
position absolute
top 115px
left 0
- width 100%
- bottom 110px
+ bottom 95px
+ width calc(100% + 15px)
overflow-y scroll
+ overflow-x scroll
nav.files-tree-nav
position absolute
@@ -104,6 +105,7 @@ body.project
line-height 24px
font-size 12px
cursor pointer
+ white-space nowrap
.name
position relative
@@ -132,24 +134,25 @@ body.project
line-height 13px
> span
- display block
- padding-left 16px * 1
+ display inline-block
+ padding-right 20px
+ padding-left 15px * 1
li > span
- padding-left 16px * 2
+ padding-left 15px * 2
li li > span
- padding-left 16px * 3
+ padding-left 15px * 3
li li li > span
- padding-left 16px * 4
+ padding-left 15px * 4
li li li li > span
- padding-left 16px * 5
+ padding-left 15px * 5
li li li li li > span
- padding-left 16px * 6
+ padding-left 15px * 6
li li li li li li > span
- padding-left 16px * 7
+ padding-left 15px * 7
li li li li li li li > span
- padding-left 16px * 8
+ padding-left 15px * 8
li li li li li li li li > span
- padding-left 16px * 9
+ padding-left 15px * 9
&.active
background #4d5b8d
@@ -175,6 +178,8 @@ body.project
background-image url('../svg/sass.svg')
&.less
background-image url('../svg/less.svg')
+ &.stylus
+ background-image url('../svg/stylus.svg')
&.css
background-image url('../svg/css.svg')
&.php
@@ -226,12 +231,12 @@ body.project
left 0
width 100%
height 110px
- padding 15px 20px 0 20px
+ padding 10px 20px 0 20px
border-top 1px solid #515771
- background rgba(0,0,0,0.2)
+ background #2c2f42
.button-container
- margin-bottom 5px
+
.button
&.switch
display inline-block
@@ -279,6 +284,7 @@ body.project
&.default
display inline-block
+ margin 10px 0
padding 5px 10px
background rgba(128,147,232,0.2)
text-decoration none
@@ -294,6 +300,7 @@ body.project
left 240px
right 0
bottom 0
+ background #31344a
section.no-file
position absolute
@@ -348,10 +355,12 @@ body.project
position absolute
top 0
left 0
- width 200px
bottom 0
+ width 215px
+ padding-bottom 5px
background #4d5b8d
overflow-y scroll
+ overflow-x hidden
a.version
display block
@@ -438,37 +447,46 @@ body.project
section.code
position absolute
top 30px
- right 0
- bottom 0
+ right -15px
+ bottom -15px
left 200px
+ background #31344a
overflow-y scroll
+ overflow-x scroll
pre
position relative
- overflow hidden
code
line-height 20px
font-family monospace
- &.lines
- position absolute
- top 0
- left 0
- width 38px
- padding 0.5em
- opacity 0.2
+ .lines
+ position absolute
+ top 0
+ left 0
+ width 38px
+ padding 0.5em
+ opacity 0.2
- &.hljs
+ .current
+ pre
+ code
+ display inline-block
+ margin-right 15px
+ margin-bottom 15px
margin-left 38px
background none
- &.differences
- position absolute
- top 0
- left 38px
- padding 0.5em
- pointer-events none
+ .differences
+ position absolute
+ top 0
+ left 38px
+ padding 0.5em
+ pointer-events none
+
+ pre
+ code
.value
visibility hidden
diff --git a/site/public/stylus/style.styl b/site/public/stylus/style.styl
index dca604a..a3b148b 100644
--- a/site/public/stylus/style.styl
+++ b/site/public/stylus/style.styl
@@ -1,3 +1,5 @@
+@import 'nib'
+
@import 'mixins/font-smoothing'
@import 'mixins/rupture'
diff --git a/site/public/svg/stylus.svg b/site/public/svg/stylus.svg
new file mode 100644
index 0000000..0d69e13
--- /dev/null
+++ b/site/public/svg/stylus.svg
@@ -0,0 +1,21 @@
+
diff --git a/site/views/pages/index/project.pug b/site/views/pages/index/project.pug
index f8cf9b4..6092972 100644
--- a/site/views/pages/index/project.pug
+++ b/site/views/pages/index/project.pug
@@ -41,17 +41,17 @@ div(ng-controller="ProjectController as controller",ng-init="init('" + project_s
.label
| created at
.value
- | 11:20:13 PM
+ | {{project.date_formated}}
.detail
.label
| last update
.value
- | 11:20:13 PM
+ | {{project.last_update_date_formated}}
.detail
.label
| files
.value
- | 32
+ | {{project.files_count}}
.aside-tree
nav.files-tree-nav
@@ -80,12 +80,6 @@ div(ng-controller="ProjectController as controller",ng-init="init('" + project_s
.text
| Choose a file
section.file(ng-if="file")
- header.file-header
- .content
- span.path
- | {{file.path.directory}}/
- span.name
- | {{file.name}}
nav.versions-nav
a.version(href="#",ng-repeat="_version in file.versions",ng-click="version_click(_version)",ng-class="_version.active ? 'active' : 'inactive'")
.background
@@ -103,18 +97,24 @@ div(ng-controller="ProjectController as controller",ng-init="init('" + project_s
.fill(style="width:{{_version.diff_percent}};")
.percent(style="width:{{_version.diff_percent}};")
| {{_version.diff_percent}}
+ header.file-header
+ .content
+ span.path
+ | {{file.path.directory}}/
+ span.name
+ | {{file.name}}
section.code
- pre
- code.lines
- - var line_index = 1
- while line_index < 999
- .line= line_index++
- code(hljs,hljs-source="version.content")
- | {{ version.content }}
- code.differences(ng-if="version.diff",ng-class="show_differences ? 'active' : 'inactive'")
- span(ng-repeat="_difference in version.diff",ng-class="{removed: _difference.removed, added: _difference.added}")
- span.value
- | {{ _difference.value }}
-
+ .lines
+ pre
+ code
+ .line(ng-repeat="_line in version.lines")
+ | {{ _line }}
+ .current(hljs,hljs-source="version.content")
+ .differences
+ pre
+ code(ng-if="version.diff",ng-class="show_differences ? 'active' : 'inactive'")
+ span(ng-repeat="_difference in version.diff",ng-class="{removed: _difference.removed, added: _difference.added}")
+ span.value
+ | {{ _difference.value }}
include ../../partials/footer.pug
diff --git a/site/views/partials/header.pug b/site/views/partials/header.pug
index 3c451c8..263e54c 100644
--- a/site/views/partials/header.pug
+++ b/site/views/partials/header.pug
@@ -18,7 +18,16 @@ html(ng-app="application")
script(src="/javascript/controllers/projects.js")
script(src="/javascript/services/project.js")
script(src="/javascript/services/projects.js")
- script(src="/javascript/models/tree.js")
+ script(src="/javascript/models/file_tree.js")
+
+ link(rel="apple-touch-icon", sizes="180x180", href="/images/icons/apple-touch-icon.png")
+ link(rel="icon", type="image/png", href="/images/icons/favicon-32x32.png", sizes="32x32")
+ link(rel="icon", type="image/png", href="/images/icons/favicon-16x16.png", sizes="16x16")
+ link(rel="manifest", href="/images/icons/manifest.json")
+ link(rel="mask-icon", href="/images/icons/safari-pinned-tab.svg", color="#5bbad5")
+ meta(name="apple-mobile-web-app-title", content="Keppler")
+ meta(name="application-name", content="Keppler")
+ meta(name="theme-color", content="#ffffff")
link(rel="stylesheet",href="/stylesheet/style.css")
link(rel="stylesheet",href="/vendors/highlight/styles/dracula.css")