file explorer working
but can't open files externally
8
.gitignore
vendored
@ -1 +1,7 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist/
|
||||
node_modules/
|
||||
thumbs.db
|
||||
yarn-error.log
|
||||
.yarnclean
|
||||
.vscode
|
||||
|
14
CHANGELOG.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
### Changed
|
||||
### Deprecated
|
||||
### Removed
|
||||
### Fixed
|
||||
### Security
|
15
README.md
@ -1 +1,14 @@
|
||||
Gestionnaire de fichier en construction!
|
||||
# Delta File Manager
|
||||
|
||||
A WIP project By [Avior](https://delta-wings.net) <florian.bouillon@delta-wings.net> (Gitlab account: [Gitlab](https://gitlab.com/aviortheking))
|
||||
|
||||
this project is licensed under the [MIT License](./LICENSE.md)
|
||||
|
||||
|
||||
## Icons
|
||||
|
||||
I used the icons from [Feather icons](https://feathericons.com) (Github link: [Github](https://github.com/feathericons/feather)) licensed under the [MIT License](https://github.com/feathericons/feather/blob/master/LICENSE)
|
||||
|
||||
## issues
|
||||
|
||||
- Actually we need to manually delete three lines from the package nunjuck loader to be able to run the dev server (index.js #21-23)
|
||||
|
@ -1,84 +0,0 @@
|
||||
# import Gitlab from 'gitlab'
|
||||
{ ProjectBundle } = require('gitlab')
|
||||
|
||||
options = {
|
||||
url: 'https://gitlab.com'
|
||||
token: ''
|
||||
}
|
||||
|
||||
gitlab = new ProjectBundle(options)
|
||||
# this is actually a test
|
||||
forceRefresh = true
|
||||
|
||||
user = undefined
|
||||
getUser = () ->
|
||||
if user is undefined or forceRefresh
|
||||
user = await gitlab.Users.current()
|
||||
user
|
||||
|
||||
projects = undefined
|
||||
getProjects = () ->
|
||||
console.log "loading Projects!"
|
||||
|
||||
if projects is undefined or forceRefresh
|
||||
console.log "loading Projects!"
|
||||
|
||||
projects = await gitlab.Projects.all { membership: true }
|
||||
console.log projects
|
||||
projects
|
||||
|
||||
project = {}
|
||||
getProject = (projectId) ->
|
||||
if projectId isnt undefined
|
||||
if project[projectId] is undefined or forceRefresh
|
||||
project[projectId] = await (gitlab.Projects).show projectId
|
||||
return project[projectId]
|
||||
return undefined
|
||||
|
||||
projectTree = {}
|
||||
getProjectTree = (projectId) ->
|
||||
if projectId isnt undefined
|
||||
if projectTree[projectId] is undefined or forceRefresh
|
||||
projectTree[projectId] = await gitlab.Repositories.tree(projectId, { recursive: true }).catch (e) ->
|
||||
console.log "pouet"
|
||||
console.log ed
|
||||
|
||||
return projectTree[projectId]
|
||||
return undefined
|
||||
|
||||
loadProjects = (parent) ->
|
||||
for el in await getProjects()
|
||||
tr = document.createElement 'tr'
|
||||
name = el.name_with_namespace.split '/'
|
||||
name.pop()
|
||||
td = "<td>" + el.id + "</td><td>" + el.name + "</td><td>" + name.join(" -> ") + "</td>"
|
||||
tr.innerHTML = td
|
||||
tr.setAttribute 'data-id', el.id
|
||||
tr.addEventListener 'click', (event) ->
|
||||
console.log event
|
||||
loadProjectTree document.querySelector(".tree"), event.target.parentNode.getAttribute("data-id")
|
||||
return
|
||||
parent.appendChild tr
|
||||
return
|
||||
|
||||
loadProjectTree = (parent, projectId) ->
|
||||
parent.innerHTML = ''
|
||||
for el in await getProjectTree projectId
|
||||
path = el.path.split "/"
|
||||
path.pop()
|
||||
tempParent = parent
|
||||
if el.type is "tree" then element = "<ul data-path=\"" + el.name + "\"></ul>"
|
||||
else element = "<li>" + el.name + "</li>"
|
||||
if path.length > 1
|
||||
tempParent = parent.querySelector "[data-path=\"" + path.pop() + "\"]"
|
||||
tempParent.innerHTML += element
|
||||
for el in parent.querySelectorAll("[data-path]")
|
||||
li = document.createElement "li"
|
||||
text = document.createTextNode el.getAttribute("data-path") + "/"
|
||||
li.appendChild text
|
||||
li.classList.add "folder"
|
||||
el.parentNode.insertBefore(li, el)
|
||||
return
|
||||
|
||||
loadProjects(document.querySelector('.projectList'))
|
||||
# console.log projects
|
31
index.html
@ -1,31 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File Name</th>
|
||||
<th>Modified</th>
|
||||
<th>Size</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</main>
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require('./renderer.js');
|
||||
// getProjects();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
56
main.js
@ -1,56 +0,0 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
66
package.json
@ -1,18 +1,64 @@
|
||||
{
|
||||
"name": "delta-file-manager",
|
||||
"version": "0.1.0",
|
||||
"description": "A customizable fiel manager",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron ."
|
||||
},
|
||||
"author": "Avior",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"electron": "^4.0.6"
|
||||
"homepage": "https://delta-wings.net/dfm",
|
||||
"author": {
|
||||
"name": "Florian bouillon",
|
||||
"email": "florian.bouillon@delta-wings.net",
|
||||
"url": "https://delta-wings.net/"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "electron-webpack dev",
|
||||
"compile": "electron-webpack",
|
||||
"dist": "yarn compile && electron-builder",
|
||||
"dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null"
|
||||
},
|
||||
"build": {
|
||||
"appId": "net.deltawings.deltafilemanager",
|
||||
"productName": "Delta File Manager",
|
||||
"copyright": "Copyright @ 2019 ${author}",
|
||||
"win": {
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": [
|
||||
"x64",
|
||||
"ia32"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
{
|
||||
"target": "deb"
|
||||
},
|
||||
{
|
||||
"target": "AppImage"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"ts-node": "^8.0.2",
|
||||
"typescript": "^3.3.3333"
|
||||
"@types/nunjucks": "^3.1.1",
|
||||
"@types/sharp": "^0.21.3",
|
||||
"source-map-support": "^0.5.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "4.0.1",
|
||||
"electron-builder": "20.38.4",
|
||||
"electron-webpack": "^2.6.2",
|
||||
"electron-webpack-ts": "^3.1.1",
|
||||
"node-sass": "^4.11.0",
|
||||
"nunjucks": "^3.2.0",
|
||||
"nunjucks-loader": "^3.0.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"typescript": "^3.3.3333",
|
||||
"webpack": "4.28.4",
|
||||
"webpack-build-notifier": "^0.1.30"
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
require("ts-node").register();
|
||||
require("./src/renderer");
|
30
src/common/Actions.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import DeltaFile from "./DeltaFile";
|
||||
import {
|
||||
sep
|
||||
} from 'path';
|
||||
import {
|
||||
getDataFolder
|
||||
} from "./Functions";
|
||||
import fs from "fs";
|
||||
|
||||
class Actions { //WIP
|
||||
|
||||
public deleteFile(file: DeltaFile) {
|
||||
let res = getDataFolder() + sep + "trash" + sep + "files" + sep + file.name;
|
||||
if(fs.existsSync(res)) {
|
||||
//rename and add it
|
||||
} else {
|
||||
//move the folder/file in the trash
|
||||
//write to infos.json about the deleted file
|
||||
}
|
||||
}
|
||||
|
||||
public emptyBin() {
|
||||
//delete all files in the trash
|
||||
}
|
||||
|
||||
//file is the file name in the trash
|
||||
public restoreDeletedFile(file: string) {
|
||||
|
||||
}
|
||||
}
|
112
src/common/DeltaFile.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import fs from 'fs';
|
||||
import {
|
||||
sep
|
||||
} from 'path';
|
||||
const icons = require("./icons.json");
|
||||
//TODO handle file redirection when no link is given
|
||||
|
||||
|
||||
export default class DeltaFile {
|
||||
|
||||
_name: string = "";
|
||||
_modetime: Date | string = "--";
|
||||
_size: number | string = "--";
|
||||
_path: string = "";
|
||||
_type: number = 0; // 0 = directory, 1 = file;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public static loadFileFromElements(name: string, path: string, type: boolean = false, modetime?: Date, size?: number): DeltaFile {
|
||||
let file = new DeltaFile();
|
||||
if(type) file.modetime = (modetime != undefined) ? modetime : "--";
|
||||
file.name = name;
|
||||
file.path = path;
|
||||
if(type) file.type = type ? 1 : 0;
|
||||
if(type) file.size = (size != undefined) ? size : "--";
|
||||
return file;
|
||||
}
|
||||
|
||||
public static loadFileFromPath(path: string): DeltaFile | undefined {
|
||||
let file = new DeltaFile();
|
||||
try {
|
||||
var stat = fs.statSync(path);
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
let name = path.split(sep).pop();
|
||||
|
||||
if(name == undefined) return undefined;
|
||||
|
||||
file.type = stat.isDirectory() ? 0 : 1;
|
||||
if(file.type != 0) {
|
||||
file.modetime = stat.mtime;
|
||||
file.size = stat.size;
|
||||
}
|
||||
file.path = path;
|
||||
file.name = name;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
public get name() : string {return this._name}
|
||||
public set name(v : string) {this._name = v}
|
||||
|
||||
public get modetime(): Date | string {return this._modetime}
|
||||
public set modetime(v: Date | string) {this._modetime = v}
|
||||
public formatTime(): string {
|
||||
if(typeof this.modetime === "string") return this.modetime;
|
||||
return this.modetime.toISOString()
|
||||
.replace(/T/, ' ')
|
||||
.replace(/\..+/, '')
|
||||
.replace(":", "/");
|
||||
}
|
||||
// 2019/03/09 04:14:01
|
||||
|
||||
public get size(): number | string {return this._size}
|
||||
public set size(v: number | string) {this._size = v}
|
||||
public formatSize(): string {
|
||||
if(typeof this.size === "string") return this.size;
|
||||
if(this.size === 0) return "0 bytes";
|
||||
let sep = 1024, d = 2;
|
||||
let ent = ["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"];
|
||||
let f = Math.floor(Math.log(this.size)/Math.log(sep));
|
||||
return parseFloat((this.size / Math.pow(sep, f)).toFixed(d)) + " " + ent[f];
|
||||
}
|
||||
|
||||
public get path(): string {return this._path}
|
||||
public set path(v: string) {this._path = v}
|
||||
|
||||
public get type(): number {return this._type}
|
||||
public set type(v: number) {this._type = v}
|
||||
|
||||
|
||||
/**
|
||||
* getThumbnail
|
||||
*/
|
||||
public getThumbnail(): string | undefined {
|
||||
//if file load picture
|
||||
//if folder see location(/home/___/pictures, /home) or name (like git, node_modules)
|
||||
if(this.type == 0) {
|
||||
for (const el in icons.folder.name) {
|
||||
if (icons.folder.name.hasOwnProperty(el)) {
|
||||
const element = icons.folder.name[el];
|
||||
if(el == this.name.toLowerCase()) return element;
|
||||
}
|
||||
}
|
||||
if(icons.folder.path[this.path] != undefined) return icons.folder.path[this.path];
|
||||
return undefined;
|
||||
} else {
|
||||
let ext = this.path.split("/").pop();
|
||||
if(ext == undefined) return undefined;
|
||||
ext = ext.split(".").pop();
|
||||
console.log(ext);
|
||||
if(ext == undefined) return undefined;
|
||||
let imgExt = ["jpg", "jpeg", "png"];
|
||||
if(imgExt.includes(ext) ) return "file://" + this.path;
|
||||
if(icons.file.extension[ext] != undefined) return icons.file.extension[ext];
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
16
src/common/Functions.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import {
|
||||
sep
|
||||
} from 'path';
|
||||
|
||||
const folderName = "delta-file-manager";
|
||||
|
||||
export function getDataFolder() {
|
||||
let platform = process.platform;
|
||||
if(platform == "win32") {
|
||||
return process.env.APP_DATA + sep + folderName;
|
||||
} else if(platform == "darwin") {
|
||||
return process.env.HOME + sep + "Library/Preferences" + sep + folderName;
|
||||
} else if(platform == "linux") {
|
||||
return process.env.HOME + sep + ".config" + sep + folderName;
|
||||
} else return undefined;
|
||||
}
|
31
src/common/icons.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"folder": {
|
||||
"name": {
|
||||
"..": "icons/chevron-left.svg",
|
||||
"git": "icons/github.svg",
|
||||
".git": "icons/github.svg",
|
||||
"pictures": "icons/image.svg",
|
||||
"music": "icons/music.svg",
|
||||
"videos": "icons/video.svg",
|
||||
"public": "icons/users.svg",
|
||||
"downloads": "icons/download.svg",
|
||||
".vscode": "icons/code.svg",
|
||||
"node_modules": "icons/package.svg",
|
||||
".config": "icons/settings.svg",
|
||||
"src": "icons/code.svg"
|
||||
},
|
||||
"path": {
|
||||
"/home": "icons/home.svg"
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"name": {
|
||||
".gitlab-ci.yaml": "icons/gitlab.svg"
|
||||
},
|
||||
"extension": {
|
||||
"code-workspace": "icons/code.svg",
|
||||
"coffee": "icons/coffee.svg"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
66
src/main/index.js
Normal file
@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import * as path from 'path'
|
||||
import { format as formatUrl } from 'url'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
// global reference to mainWindow (necessary to prevent window from being garbage collected)
|
||||
let mainWindow
|
||||
|
||||
function createMainWindow() {
|
||||
const window = new BrowserWindow({
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
if (isDevelopment) {
|
||||
window.webContents.openDevTools()
|
||||
}
|
||||
|
||||
if (isDevelopment) {
|
||||
window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`)
|
||||
}
|
||||
else {
|
||||
window.loadURL(formatUrl({
|
||||
pathname: path.join(__dirname, 'index.html'),
|
||||
protocol: 'file',
|
||||
slashes: true
|
||||
}))
|
||||
}
|
||||
|
||||
window.on('closed', () => {
|
||||
mainWindow = null
|
||||
})
|
||||
|
||||
window.webContents.on('devtools-opened', () => {
|
||||
window.focus()
|
||||
setImmediate(() => {
|
||||
window.focus()
|
||||
})
|
||||
})
|
||||
|
||||
return window
|
||||
}
|
||||
|
||||
// quit application when all windows are closed
|
||||
app.on('window-all-closed', () => {
|
||||
// on macOS it is common for applications to stay open until the user explicitly quits
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
// on macOS it is common to re-create a window even after all windows have been closed
|
||||
if (mainWindow === null) {
|
||||
mainWindow = createMainWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// create main BrowserWindow when electron is ready
|
||||
app.on('ready', () => {
|
||||
mainWindow = createMainWindow()
|
||||
})
|
@ -1,69 +0,0 @@
|
||||
import { sep } from 'path';
|
||||
import { Stats } from "fs";
|
||||
const fs = require("fs");
|
||||
import { shell } from 'electron';
|
||||
|
||||
const loader = document.querySelector("tbody");
|
||||
const rootPath = '/';
|
||||
|
||||
|
||||
const loadFolder = (path: string) => {
|
||||
loader.innerHTML = "";
|
||||
|
||||
if(path != rootPath) {
|
||||
let pt = path.split("/");
|
||||
pt.pop();
|
||||
console.log(rootPath);
|
||||
console.log(pt.join("/"));
|
||||
let pouet = "" == pt.join("/") ? sep : pt.join("/");
|
||||
addElement("..", pouet);
|
||||
}
|
||||
fs.readdir(path, (err, items) => {
|
||||
for (const item of items) {
|
||||
console.log(path);
|
||||
let it = path == "/" ? path + item : path + sep + item;
|
||||
fs.stat(it, (err, stat) => {
|
||||
// console.log(err);
|
||||
let pth = path == "/" ? path + item : path + sep + item;
|
||||
addElement(item, pth, stat);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function addElement(filename: string, path: string, stat: Stats = null) {
|
||||
let mtime = stat != null ? stat.mtime : null;
|
||||
let classe = stat != null ? (stat.isDirectory() ? "folder" : "file") : "folder";
|
||||
if(stat != null) var month = (mtime.getUTCMonth() + 1) > 10 ? "0" + (mtime.getUTCMonth() + 1) : "" + (mtime.getUTCMonth() + 1);
|
||||
else var month = "0";
|
||||
let time = stat == null || stat.isDirectory() ? "--" : mtime.getUTCFullYear() + "/" + month + "/" + mtime.getUTCDate();
|
||||
let bytes = stat == null || stat.isDirectory() ? "--" : formatBytes(stat.size);
|
||||
let tr = document.createElement("tr");
|
||||
tr.classList.add(classe);
|
||||
tr.setAttribute("data-file", path);
|
||||
tr.addEventListener("click", function() {
|
||||
if(this.classList.contains("folder")) loadFolder(this.getAttribute("data-file"));
|
||||
else loadFile(this.getAttribute("data-file"));
|
||||
});
|
||||
for (const el of [filename, time, bytes]) {
|
||||
let td = document.createElement("td");
|
||||
td.innerText = el;
|
||||
tr.appendChild(td);
|
||||
}
|
||||
loader.appendChild(tr);
|
||||
}
|
||||
|
||||
function formatBytes(integ: number): string {
|
||||
if(integ === 0) return "0 bytes";
|
||||
let sep = 1024, d = 2;
|
||||
let ent = ["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"];
|
||||
let f = Math.floor(Math.log(integ)/Math.log(sep));
|
||||
return parseFloat((integ / Math.pow(sep, f)).toFixed(d)) + " " + ent[f];
|
||||
}
|
||||
|
||||
function loadFile(file: string) {
|
||||
shell.openItem(file);
|
||||
}
|
||||
|
||||
loadFolder("/");
|
38
src/renderer/fileRenderers/blocks.njk
Normal file
@ -0,0 +1,38 @@
|
||||
{% extends "../index.njk" %}
|
||||
|
||||
{% block filelist %}
|
||||
|
||||
<div class="grid">
|
||||
{% for file in files %}
|
||||
{% if file.type == "0" %}
|
||||
{% set thumb = file.getThumbnail() %}
|
||||
{% if thumb != undefined %}
|
||||
<div class="grid-item folder" data-file={{ file.path }} style="background-image: url({{ thumb }})">
|
||||
{% else %}
|
||||
<div class="grid-item folder" data-file={{ file.path }}>
|
||||
{% endif %}
|
||||
{{file.name}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
{% for file in files %}
|
||||
{% if file.type == "1" %}
|
||||
<div class="grid-item file" data-file="{{ file.path }}">
|
||||
{% if file.getThumbnail() != undefined %}
|
||||
<div class="item-preview" style='background-image: url("{{ file.getThumbnail() }}")'>
|
||||
{% else %}
|
||||
<div class="item-preview null">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="item-name">{{ file.name }}</div>
|
||||
<div class="item-size">{{ file.formatSize() }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
23
src/renderer/fileRenderers/list.njk
Normal file
@ -0,0 +1,23 @@
|
||||
{% extends "../index.njk" %}
|
||||
|
||||
{% block filelist %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Last Time modified</th>
|
||||
<th>Size</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for file in files %}
|
||||
<tr data-file="{{ file.path }}">
|
||||
<td>{{ file.name }}</td>
|
||||
<td>{{ file.formatTime() }}</td>
|
||||
<td>{{ file.formatSize() }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
{% endblock %}
|
5
src/renderer/index.njk
Normal file
@ -0,0 +1,5 @@
|
||||
<aside>
|
||||
</aside>
|
||||
<main>
|
||||
{% block filelist %}{% endblock %}
|
||||
</main>
|
52
src/renderer/index.ts
Normal file
@ -0,0 +1,52 @@
|
||||
// import { render as nunjuckRender} from 'nunjucks';
|
||||
import fs from 'fs';
|
||||
import { sep } from 'path';
|
||||
import DeltaFile from '../common/DeltaFile';
|
||||
import './style.scss';
|
||||
import { Template } from 'nunjucks';
|
||||
|
||||
const tpl: Template = require("./fileRenderers/blocks.njk");
|
||||
|
||||
const rootPath = "/";
|
||||
|
||||
const loadFolder = (path: string) => {
|
||||
let results = [];
|
||||
if(path != rootPath) {
|
||||
let pt = path.split("/");
|
||||
pt.pop();
|
||||
let pouet = "" == pt.join("/") ? sep : pt.join("/");
|
||||
results.push(DeltaFile.loadFileFromElements("..", pouet, false));
|
||||
}
|
||||
let items = fs.readdirSync(path);
|
||||
|
||||
for (const item of items) {
|
||||
let pth = path == "/" ? path + item : path + sep + item;
|
||||
let file = DeltaFile.loadFileFromPath(pth);
|
||||
if(file != undefined)results.push(file);
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
}
|
||||
|
||||
const showFolder = (folder: string) => {
|
||||
let app = document.getElementById("app");
|
||||
if(app == undefined) app = document.body;
|
||||
var els = loadFolder(folder);
|
||||
app.innerHTML = tpl.render({files: els});
|
||||
app.querySelectorAll("[data-file]").forEach((el) => {
|
||||
el.addEventListener("click", function(this: HTMLElement) {
|
||||
// console.log(this);
|
||||
let folder = this.getAttribute("data-file");
|
||||
if(folder != null) showFolder(folder);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showFolder("/");
|
||||
|
||||
// function loadFile(file: string) {
|
||||
// shell.openItem(file);
|
||||
// }
|
||||
// console.log(render("index.njk"));
|
||||
// console.log(loadFolder("/"));
|
110
src/renderer/style.scss
Normal file
@ -0,0 +1,110 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
width: calc(100% - 60px);
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-gap: 30px;
|
||||
place-items: stretch;
|
||||
// justify-content: center;
|
||||
padding: 30px;
|
||||
@media (max-width: 1190px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@media (max-width: 960px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@media (max-width: 721px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
@media (max-width: 502px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
> .grid-item {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space:nowrap;
|
||||
background-repeat: no-repeat;
|
||||
justify-self: stretch;
|
||||
min-width: 150px;
|
||||
cursor: pointer;
|
||||
|
||||
&.folder {
|
||||
background-image: url(../../static/icons/folder.svg);
|
||||
background-size: 30px;
|
||||
background-position-y: center;
|
||||
background-position-x: 10px;
|
||||
// min-width: 150px;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
border: 1px solid rgba(0,0,0,.1);
|
||||
padding: 10px .5%;
|
||||
padding-left: calc(.5% + 45px);
|
||||
border-radius: 10px;
|
||||
color: rgba(0, 0, 0, .8);
|
||||
|
||||
transition-property: box-shadow, transform, background-color;
|
||||
transition-duration: 200ms;
|
||||
transition-timing-function: ease-in-out;
|
||||
&:hover {
|
||||
box-shadow: 0px 5px 0px 0px rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
&:active {
|
||||
box-shadow: 0px -0px 0px 0px rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.file {
|
||||
border-radius: 10px;
|
||||
transition-property: box-shadow, transform, background-color;
|
||||
transition-duration: 200ms;
|
||||
transition-timing-function: ease-in-out;
|
||||
&:hover {
|
||||
box-shadow: 0px 5px 0px 0px rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
&:active {
|
||||
box-shadow: 0px -0px 0px 0px rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
transform: translateY(0px);
|
||||
}
|
||||
.item-preview {
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
height: 150px;
|
||||
box-shadow: inset 0 0 20px 0 rgba(0, 0, 0, .1);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
&.null {
|
||||
background-image: url(../../static/icons/file.svg);
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
margin: 10px;
|
||||
font-size: 20px;
|
||||
color: rgba(0, 0, 0, .8)
|
||||
}
|
||||
|
||||
.item-size {
|
||||
color: rgba(0, 0, 0, .5);
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
user-select: none;
|
||||
}
|
1
static/icons/chevron-left.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
After Width: | Height: | Size: 270 B |
1
static/icons/code.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-code"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
|
After Width: | Height: | Size: 307 B |
1
static/icons/coffee.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-coffee"><path d="M18 8h1a4 4 0 0 1 0 8h-1"></path><path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z"></path><line x1="6" y1="1" x2="6" y2="4"></line><line x1="10" y1="1" x2="10" y2="4"></line><line x1="14" y1="1" x2="14" y2="4"></line></svg>
|
After Width: | Height: | Size: 447 B |
1
static/icons/download.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-download"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
|
After Width: | Height: | Size: 370 B |
1
static/icons/file.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>
|
After Width: | Height: | Size: 337 B |
1
static/icons/folder.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-folder"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
|
After Width: | Height: | Size: 311 B |
1
static/icons/github.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-github"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
|
After Width: | Height: | Size: 527 B |
1
static/icons/gitlab.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-gitlab"><path d="M22.65 14.39L12 22.13 1.35 14.39a.84.84 0 0 1-.3-.94l1.22-3.78 2.44-7.51A.42.42 0 0 1 4.82 2a.43.43 0 0 1 .58 0 .42.42 0 0 1 .11.18l2.44 7.49h8.1l2.44-7.51A.42.42 0 0 1 18.6 2a.43.43 0 0 1 .58 0 .42.42 0 0 1 .11.18l2.44 7.51L23 13.45a.84.84 0 0 1-.35.94z"></path></svg>
|
After Width: | Height: | Size: 490 B |
1
static/icons/home.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
|
After Width: | Height: | Size: 332 B |
1
static/icons/icons.md
Normal file
@ -0,0 +1 @@
|
||||
source : https://feathericons.com/
|
1
static/icons/image.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-image"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
|
After Width: | Height: | Size: 369 B |
1
static/icons/music.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-music"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg>
|
After Width: | Height: | Size: 327 B |
1
static/icons/package.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-package"><path d="M12.89 1.45l8 4A2 2 0 0 1 22 7.24v9.53a2 2 0 0 1-1.11 1.79l-8 4a2 2 0 0 1-1.79 0l-8-4a2 2 0 0 1-1.1-1.8V7.24a2 2 0 0 1 1.11-1.79l8-4a2 2 0 0 1 1.78 0z"></path><polyline points="2.32 6.16 12 11 21.68 6.16"></polyline><line x1="12" y1="22.76" x2="12" y2="11"></line><line x1="7" y1="3.5" x2="17" y2="8.5"></line></svg>
|
After Width: | Height: | Size: 538 B |
1
static/icons/settings.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
|
After Width: | Height: | Size: 1011 B |
1
static/icons/users.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
|
After Width: | Height: | Size: 400 B |
1
static/icons/video.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-video"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg>
|
After Width: | Height: | Size: 329 B |
@ -14,13 +14,18 @@ table th {
|
||||
}
|
||||
|
||||
table tr {
|
||||
border-bottom: 1px solid #212121;
|
||||
border-bottom: 1px solid #aaa;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
table tr td {
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
table tr td:first-child {
|
||||
padding-left: 60px;
|
||||
background-repeat: no-repeat;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
table tr.folder td:first-child {
|
||||
|
3
tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "./node_modules/electron-webpack/tsconfig-base.json"
|
||||
}
|