file explorer working

but can't open files externally
This commit is contained in:
2019-03-10 01:13:57 +01:00
parent 9628c2cd42
commit efc0a0e1b9
38 changed files with 7540 additions and 350 deletions

30
src/common/Actions.ts Normal file
View 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
View 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
View 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
View 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
View 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()
})

View File

@ -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("/");

View 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 %}

View 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
View File

@ -0,0 +1,5 @@
<aside>
</aside>
<main>
{% block filelist %}{% endblock %}
</main>

52
src/renderer/index.ts Normal file
View 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
View 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;
}