Implemented file info modal

This commit is contained in:
Chris Kankiewicz
2019-12-22 01:17:16 -07:00
parent 3b93044062
commit b6830c1d49
9 changed files with 2710 additions and 2170 deletions

View File

@@ -2,12 +2,25 @@
namespace App\Controllers;
use RuntimeException;
use PHLAK\Config\Config;
use Slim\Psr7\Response;
use SplFileInfo;
class FileInfoController
{
/** @var Config App configuration component */
protected $config;
/**
* Create a new FileInfoController object.
*
* @param \PHLAK\Config\Config $config
*/
public function __construct(Config $config)
{
$this->config = $config;
}
/**
* Invoke the FileInfoController.
*
@@ -17,10 +30,13 @@ class FileInfoController
public function __invoke(Response $response, string $path = '.')
{
if (! is_file($path)) {
throw new RuntimeException('Invalid file path', $path);
return $response->withStatus(404, 'File not found');
}
$file = new SplFileInfo($path);
if ($file->getSize() >= $this->config->get('max_hash_size', 1000000000)) {
return $response->withStatus(500, 'File size too large');
}
$response->getBody()->write(json_encode([
'hashes' => [

View File

@@ -53,4 +53,12 @@ return [
* Default value: true
*/
'ignore_vcs_files' => true,
/**
* The maximum file size (in bytes) that can be hashed. This helps to
* prevent timeouts for excessively large files.
*
* Defualt value: 1000000000
*/
'max_hash_size' => 1000000000
];

View File

@@ -1,36 +1,45 @@
<a
href="{% if parentDir %}..{% else %}{{ file.getRelativePathname }}{% endif %}"
class="flex justify-between items-center rounded-lg p-4 hover:bg-gray-200 hover:p-4 hover:shadow"
href="{{ parentDir ? '..' : file.getRelativePathname }}"
class="flex flex-col items-center rounded-lg group hover:bg-gray-200 hover:shadow"
>
<div class="flex-shrink pr-2">
{% if parentDir %}
<i class="fas fa-level-up-alt fa-fw fa-lg"></i>
{% else %}
{{ icon(file) | raw }}
{% endif %}
</div>
<div class="flex justify-between items-center p-4 w-full">
<div class="flex-shrink pr-2">
{% if parentDir %}
<i class="fas fa-level-up-alt fa-fw fa-lg"></i>
{% else %}
{{ icon(file) | raw }}
{% endif %}
</div>
<div class="flex-grow truncate mr-2">
{% if parentDir %}
..
{% else %}
{{ file.getBasename }}
{% endif %}
</div>
<div class="flex-grow sm:mr-2">
<div class="flex justify-between">
<div class="truncate">
{{ parentDir ? '..' : file.getBasename }}
</div>
<div class="hidden whitespace-no-wrap text-right mx-2 w-1/6 sm:block">
{% if parentDir or file.isDir %}
{% else %}
{{ sizeForHumans(file.getSize) }}
{% endif %}
</div>
{% if file.isFile %}
<div class="ml-2">
<button
class="flex justify-center items-center rounded-full text-sm p-2 -m-1 invisible hover:bg-gray-400 hover:shadow group-hover:visible"
v-on:click.prevent="showFileInfo('{{ file.getPathname }}')"
>
<i class="fas fa-info-circle"></i>
</button>
</div>
{% endif %}
</div>
</div>
<div class="hidden whitespace-no-wrap text-right truncate ml-2 w-1/4 sm:block">
{% if parentDir %}
{% else %}
{{ file.getMTime | date }}
{% endif %}
<div class="hidden whitespace-no-wrap text-right mx-2 w-1/6 sm:block">
{% if parentDir or file.isDir %}
{% else %}
{{ sizeForHumans(file.getSize) }}
{% endif %}
</div>
<div class="hidden whitespace-no-wrap text-right truncate ml-2 w-1/4 sm:block">
{{ parentDir ? '—' : file.getMTime | date }}
</div>
</div>
</a>

View File

@@ -2,11 +2,13 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="{{ asset('dist/app.js') }}" defer></script>
<link rel="stylesheet" href="{{ asset('dist/app.css') }}">
<title>Directory Lister</title>
<div id="app" class="font-mono min-h-screen {{ config('dark_mode') ? 'dark-mode' : '' }}">
<div id="app" class="font-mono min-h-screen z-0 {{ config('dark_mode') ? 'dark-mode' : '' }}">
<header id="header" class="block bg-blue-600 shadow sticky top-0 text-white text-sm tracking-tight">
<div class="container mx-auto p-4">
<a href="/" class="hover:underline">Home</a>
@@ -57,16 +59,6 @@
>
<i class="fas fa-arrow-up fa-lg"></i>
</a>
<file-info-modal ref="fileInfoModal"></file-info-modal>
</div>
<script>
let link = document.getElementById('scroll-to-top');
window.addEventListener('scroll', function() {
if (window.scrollY > 10) {
link.classList.remove('hidden');
} else {
link.classList.add('hidden');
}
});
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -9,16 +9,19 @@
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"dependencies": {
"axios": "^0.19.0",
"vue": "^2.6.11"
},
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.12.0",
"cross-env": "^6.0.3",
"laravel-mix": "^5.0.0",
"laravel-mix": "^5.0.1",
"laravel-mix-purgecss": "^4.2.0",
"resolve-url-loader": "^3.1.1",
"sass": "^1.23.7",
"sass": "^1.24.0",
"sass-loader": "^8.0.0",
"tailwindcss": "^1.1.4",
"vue-template-compiler": "^2.6.11"
},
"dependencies": {}
}
}

View File

@@ -0,0 +1,21 @@
window.Vue = require('vue');
Vue.component('file-info-modal', require('./components/file-info-modal.vue').default);
const app = new Vue({
el: "#app",
methods: {
showFileInfo(filePath) {
this.$refs.fileInfoModal.show(filePath);
}
}
});
let link = document.getElementById('scroll-to-top');
window.addEventListener('scroll', function() {
if (window.scrollY > 10) {
link.classList.remove('hidden');
} else {
link.classList.add('hidden');
}
});

View File

@@ -0,0 +1,86 @@
<template>
<div
class="fixed top-0 flex justify-center items-center w-screen h-screen p-4 z-50"
style="background-color: hsla(218, 23%, 23%, .5)"
v-bind:class="this.styles"
>
<div class="bg-white rounded-lg shadow-lg overflow-hidden" v-show="! loading">
<div class="flex justify-between items-center bg-blue-600 p-4">
<i class="fas fa-info-circle fa-lg text-white"></i>
<div class="items-center text-xl text-white font-mono mx-4">
{{ title }}
</div>
<button
class="flex justify-center items-center rounded-full w-6 h-6 text-blue-900 text-sm hover:bg-red-700 hover:text-white hover:shadow"
v-on:click="hide()"
>
<i class="fas fa-times"></i>
</button>
</div>
<div class="flex justify-center items-center p-4">
<div class="overflow-x-auto">
<table class="table-auto">
<tbody>
<tr v-for="(hash, title) in this.hashes" v-bind:key="hash">
<td class="border font-bold px-4 py-2">{{ title }}</td>
<td class="border px-4 py-2">{{ hash }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<i class="fas fa-spinner fa-pulse fa-5x text-white" v-show="loading"></i>
</div>
</template>
<script>
const axios = require('axios').default;
export default {
data: function () {
return {
filePath: 'file-info.txt',
hashes: {
'md5': '••••••••••••••••••••••••••••••••',
'sha1': '••••••••••••••••••••••••••••••••••••••••',
'sha256': '••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••'
},
loading: true,
visible: false,
};
},
computed: {
styles() {
return { 'hidden': ! this.visible };
},
title() {
return this.filePath.split('/').pop();
}
},
methods: {
async show(filePath) {
this.filePath = filePath;
this.visible = true;
await axios.get('/file-info/' + filePath).then(function (response) {
this.hashes = response.data.hashes;
this.loading = false;
}.bind(this)).catch(
response => this.hide() && console.error(response)
);
},
hide() {
this.visible = false;
this.loading = true;
}
},
mounted() {
window.addEventListener('keyup', e => e.keyCode == 27 && this.hide());
}
}
</script>

View File

@@ -1,7 +1,9 @@
module.exports = {
theme: {
extend: {}
},
variants: {},
plugins: []
}
theme: {
extend: {}
},
variants: {
visibility: ['responsive', 'hover', 'group-hover']
},
plugins: []
};