mirror of
https://github.com/Aviortheking/Delta-File-Manager.git
synced 2025-07-29 15:19:49 +00:00
file explorer working
but can't open files externally
This commit is contained in:
30
src/common/Actions.ts
Normal file
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
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
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
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
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
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
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
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
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
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;
|
||||
}
|
Reference in New Issue
Block a user