diff options
28 files changed, 483 insertions, 29 deletions
diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index b32469c8574..06806309cac 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -62,6 +62,16 @@ $application->registerRoutes( 'verb' => 'POST' ], [ + 'name' => 'API#showGridView', + 'url' => '/api/v1/showgridview', + 'verb' => 'POST' + ], + [ + 'name' => 'API#getGridView', + 'url' => '/api/v1/showgridview', + 'verb' => 'GET' + ], + [ 'name' => 'view#index', 'url' => '/', 'verb' => 'GET', diff --git a/apps/files/css/files.scss b/apps/files/css/files.scss index 05c9de43a24..a643cb6258f 100644 --- a/apps/files/css/files.scss +++ b/apps/files/css/files.scss @@ -172,7 +172,7 @@ table th, table th a { color: var(--color-text-maxcontrast); } table.multiselect th a { - color: #000; + color: var(--color-main-text); } table th .columntitle { display: block; @@ -262,8 +262,7 @@ table.multiselect thead { } table.multiselect thead th { - background-color: rgba(255, 255, 255, 0.95); /* like controls bar */ - color: #000; + background-color: var(--color-main-background); font-weight: bold; border-bottom: 0; } @@ -595,7 +594,13 @@ a.action > img { .summary { opacity: .3; /* add whitespace to bottom of files list to correctly show dropdowns */ - height: 300px; + height: 250px; +} +/* Less whitespace needed on link share page + * as there is a footer and action menus have fewer entries. + */ +#body-public .summary { + height: 180px; } .summary:hover, .summary:focus, @@ -723,3 +728,277 @@ table.dragshadow td.size { height: 30px; line-height: 30px; } + +/* GRID */ +#filestable.view-grid:not(.hidden) { + $grid-size: 160px; + $grid-pad: 14px; + + /* HEADER and MULTISELECT */ + thead { + tr { + display: block; + border-bottom: 1px solid var(--color-border); + background-color: var(--color-main-background); + th { + width: auto; + border: none; + } + } + } + + /* MAIN FILE LIST */ + tbody { + display: grid; + grid-template-columns: repeat(auto-fill, $grid-size); + justify-content: space-around; + row-gap: 15px; + margin: 15px 0; + + tr { + display: block; + position: relative; + height: $grid-size + 44px - $grid-pad; + border-radius: var(--border-radius); + + &:hover, &:focus, &:active, + &.selected, + &.searchresult, + .name:focus, + &.highlighted { + background-color: transparent; + + .thumbnail-wrapper, + .nametext, + .fileactions { + transition: background-color 0.3s ease; + background-color: var(--color-background-dark); + } + } + } + + td { + display: inline; + border-bottom: none; + + &.filename { + .thumbnail-wrapper { + min-width: 0; + max-width: none; + position: absolute; + width: $grid-size; + height: $grid-size; + padding: $grid-pad; // same as action icon bottom and right padding + top: 0; + left: 0; + z-index: -1; // make sure the default click is the link + + .thumbnail { + width: calc(100% - 2 * #{$grid-pad}); + height: calc(100% - 2 * #{$grid-pad}); //action icon padding + background-size: contain; + margin: 0; + border-radius: var(--border-radius); + background-repeat: no-repeat; + background-position: center; + + /* Position favorite star related to checkbox to left and 3-dot menu below + * Position is inherited from the selection while in grid view + */ + .favorite-mark { + padding: $grid-pad; + left: auto; + top: -22px; // center in corner of thumbnail + right: -22px; // center in corner of thumbnail + } + } + } + + .name { + height: 100%; + border-radius: var(--border-radius); + // since we're using thumbnail, name and actions bg + // we need to hide the overflow for the radius to show + // luckily the popovermenu is outside .name + overflow: hidden; + // we but the thumbnail in background to ensure + // the name is the default click handler + // force back the cursor which have been overrided + // and disabled for some reason... + cursor: pointer !important; + + .nametext { + display: flex; + height: 44px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-top: $grid-size - $grid-pad; + padding-right: 0; + text-align: right; + line-height: 44px; + padding-left: $grid-pad; // same as action icon right padding + + .innernametext { + display: inline-block; + max-width: 80px; + } + + /* No space for extension in grid view */ + .extension { + display: none; + } + } + + .fileactions { + height: initial; + margin-top: $grid-size - $grid-pad; + display: flex; + align-items: center; + + .action { + padding: $grid-pad; + width: 44px; + height: 44px; + display: flex; + align-items: center; + justify-content: center; + + &.action-share.permanent.shared-style span { + /* Do not show "Shared" text next to icon as there is no space */ + &:not(.icon) { + display: none; + } + + /* If an avatar is present, show that instead of the icon */ + &.avatar { + display: inline-block; + position: absolute; + } + } + + /* In "Deleted files", do not show "Restore" text next to icon as there is no space */ + &.action-restore.permanent span { + &:not(.icon) { + display: none; + } + } + + /* If there is a comment, show it instead of the share icon */ + &.action-comment ~ .action-share { + display: none; + } + } + } + } + } + + /* No space for filesize and date in grid view */ + &.filesize, + &.date { + display: none; + } + + &.selection, + &.filename .favorite-mark { + position: absolute; + top: -8px; // half the checkbox width, center on corner of thumbnail + left: -8px; // half the checkbox width, center on corner of thumbnail + display: flex; + width: 44px; + height: 44px; + z-index: 10; + background: transparent; + + label { + width: 44px; + height: 44px; + display: inline-flex; + padding: $grid-pad; // like any action icon + &::before { + margin: 0; + width: $grid-pad; // 16px - border + height: $grid-pad; // 16px - border + } + } + } + + /* Position actions menu below file */ + .popovermenu { + left: 0; + width: $grid-size - 10px; // 2 * margin + margin: 0 5px; + + /* Ellipsize long entries, normally menu width is adjusted but for grid we use fixed width. */ + .menuitem span:not(.icon) { + overflow: hidden; + text-overflow: ellipsis; + } + } + } + } + + /* Center align the footer file number & size summary */ + tfoot { + display: grid; + + .summary:not(.hidden) { + display: inline-block; + margin: 0 auto; + + td { + padding-top: 50px; + + &:first-child, + &.date { + display: none; + } + + .info { + margin-left: 0; + } + } + } + } +} + +/* Grid view toggle */ +#view-toggle { + background-color: transparent; + border: none; + margin: 0; + padding: 22px; + opacity: .5; + + &:hover, + &:focus, + #showgridview:focus + & { + opacity: 1; + } +} + +/* Adjustments for link share page */ +#body-public { + #filestable.view-grid:not(.hidden) tbody td { + /* More space for filename since there is no share icon */ + &.filename .name .nametext .innernametext { + max-width: 124px; + } + + /* Position actions menu correctly below 3-dot-menu */ + .popovermenu { + left: -80px; + } + } + + /* Right-align view toggle on link share page */ + #view-toggle { + position: absolute; + right: 0; + } +} + +/* Hide legacy Gallery toggle */ +#gallery-button { + display: none; +} diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 2211505f6d5..9cc1856d52b 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -331,6 +331,11 @@ this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this)); + // Toggle for grid view + this.$showGridView = $('input#showgridview'); + this.$showGridView.on('change', _.bind(this._onGridviewChange, this)); + $('#view-toggle').tooltip({placement: 'bottom', trigger: 'hover'}); + this._onResize = _.debounce(_.bind(this._onResize, this), 250); $('#app-content').on('appresized', this._onResize); $(window).resize(this._onResize); @@ -592,6 +597,26 @@ }, /** + * Toggle showing gridview by default or not + * + * @returns {undefined} + */ + _onGridviewChange: function() { + var show = this.$showGridView.is(':checked'); + // only save state if user is logged in + if (OC.currentUser) { + $.post(OC.generateUrl('/apps/files/api/v1/showgridview'), { + show: show + }); + } + this.$showGridView.next('#view-toggle') + .removeClass('icon-toggle-filelist icon-toggle-pictures') + .addClass(show ? 'icon-toggle-filelist' : 'icon-toggle-pictures') + + $('.list-container').toggleClass('view-grid', show); + }, + + /** * Event handler when leaving previously hidden state */ _onShow: function(e) { @@ -2776,7 +2801,9 @@ var permissions = this.getDirectoryPermissions(); var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty); + this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty); this.$el.find('#emptycontent .uploadmessage').toggleClass('hidden', !isCreatable || !this.isEmpty); + this.$el.find('#filestable').toggleClass('hidden', this.isEmpty); this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty); }, /** diff --git a/apps/files/lib/Controller/ApiController.php b/apps/files/lib/Controller/ApiController.php index 27cd0b361c5..3085b72ac7a 100644 --- a/apps/files/lib/Controller/ApiController.php +++ b/apps/files/lib/Controller/ApiController.php @@ -38,6 +38,7 @@ use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\IRequest; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\FileDisplayResponse; use OCP\AppFramework\Http\Response; use OCA\Files\Service\TagService; @@ -268,6 +269,28 @@ class ApiController extends Controller { } /** + * Toggle default for files grid view + * + * @NoAdminRequired + * + * @param bool $show + */ + public function showGridView($show) { + $this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', (int)$show); + return new Response(); + } + + /** + * Get default settings for the grid view + * + * @NoAdminRequired + */ + public function getGridView() { + $status = $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', '1') === '1'; + return new JSONResponse(['gridview' => $status]); + } + + /** * Toggle default for showing/hiding xxx folder * * @NoAdminRequired diff --git a/apps/files/list.php b/apps/files/list.php index 93044d4c587..f18dc5964b8 100644 --- a/apps/files/list.php +++ b/apps/files/list.php @@ -22,11 +22,14 @@ */ $config = \OC::$server->getConfig(); +$userSession = \OC::$server->getUserSession(); // TODO: move this to the generated config.js $publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'); +$showgridview = $config->getUserValue($userSession->getUser()->getUID(), 'files', 'show_grid', true); // renders the controls and table headers template $tmpl = new OCP\Template('files', 'list', ''); $tmpl->assign('publicUploadEnabled', $publicUploadEnabled); +$tmpl->assign('showgridview', $showgridview); $tmpl->printPage(); diff --git a/apps/files/templates/list.php b/apps/files/templates/list.php index 9cae72a176f..27403594368 100644 --- a/apps/files/templates/list.php +++ b/apps/files/templates/list.php @@ -24,6 +24,10 @@ <?php endif;?> <input type="hidden" class="max_human_file_size" value="(max <?php isset($_['uploadMaxHumanFilesize']) ? p($_['uploadMaxHumanFilesize']) : ''; ?>)"> + <input type="checkbox" class="hidden-visually" id="showgridview" + <?php if($_['showgridview']) { ?>checked="checked" <?php } ?>/> + <label id="view-toggle" for="showgridview" class="button <?php p($_['showgridview'] ? 'icon-toggle-filelist' : 'icon-toggle-pictures') ?>" + title="<?php p($l->t('Toggle grid view'))?>"></label> </div> <div id="emptycontent" class="hidden"> @@ -38,7 +42,7 @@ <p></p> </div> -<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="32" data-preview-y="32"> +<table id="filestable" class="list-container <?php p($_['showgridview'] ? 'view-grid' : '') ?>" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="250" data-preview-y="250"> <thead> <tr> <th id="headerSelection" class="hidden column-selection"> diff --git a/apps/files/templates/recentlist.php b/apps/files/templates/recentlist.php index cfdb95c80a0..4c269c20256 100644 --- a/apps/files/templates/recentlist.php +++ b/apps/files/templates/recentlist.php @@ -11,7 +11,7 @@ <p></p> </div> -<table id="filestable"> +<table id="filestable" class="list-container view-grid"> <thead> <tr> <th id='headerName' class="hidden column-name"> diff --git a/apps/files/templates/simplelist.php b/apps/files/templates/simplelist.php index 78adb21922f..a99607ea642 100644 --- a/apps/files/templates/simplelist.php +++ b/apps/files/templates/simplelist.php @@ -13,7 +13,7 @@ <h2><?php p($l->t('No entries found in this folder')); ?></h2> <p></p> </div> -<table id="filestable"> +<table id="filestable" class="list-container view-grid"> <thead> <tr> <th id='headerName' class="hidden column-name"> diff --git a/apps/files/tests/js/favoritesfilelistspec.js b/apps/files/tests/js/favoritesfilelistspec.js index d1421c84ee2..5a206ca4dec 100644 --- a/apps/files/tests/js/favoritesfilelistspec.js +++ b/apps/files/tests/js/favoritesfilelistspec.js @@ -25,7 +25,7 @@ describe('OCA.Files.FavoritesFileList tests', function() { '</div>' + // dummy table // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead><tr>' + '<th id="headerName" class="hidden column-name">' + '<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' + diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js index 6dde2734f1d..ca88461fafb 100644 --- a/apps/files/tests/js/fileUploadSpec.js +++ b/apps/files/tests/js/fileUploadSpec.js @@ -117,7 +117,7 @@ describe('OC.Upload tests', function() { beforeEach(function() { $('#testArea').append( '<div id="tableContainer">' + - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead><tr>' + '<th id="headerName" class="hidden column-name">' + '<input type="checkbox" id="select_all_files" class="select-all">' + diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js index 00d13859b5b..024993b310d 100644 --- a/apps/files/tests/js/fileactionsSpec.js +++ b/apps/files/tests/js/fileactionsSpec.js @@ -28,7 +28,7 @@ describe('OCA.Files.FileActions tests', function() { var $body = $('#testArea'); $body.append('<input type="hidden" id="dir" value="/subdir"></input>'); $body.append('<input type="hidden" id="permissions" value="31"></input>'); - $body.append('<table id="filestable"><tbody id="fileList"></tbody></table>'); + $body.append('<table id="filestable" class="list-container view-grid"><tbody id="fileList"></tbody></table>'); // dummy files table fileActions = new OCA.Files.FileActions(); fileActions.registerAction({ diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 04102a84754..961761c3e86 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -88,7 +88,7 @@ describe('OCA.Files.FileList tests', function() { '<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' + // dummy table // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead><tr>' + '<th id="headerName" class="hidden column-name">' + '<input type="checkbox" id="select_all_files" class="select-all checkbox">' + diff --git a/apps/files_external/templates/list.php b/apps/files_external/templates/list.php index ed13ed83701..20f97dd4c08 100644 --- a/apps/files_external/templates/list.php +++ b/apps/files_external/templates/list.php @@ -11,7 +11,7 @@ <input type="hidden" name="dir" value="" id="dir"> -<table id="filestable"> +<table id="filestable" class="list-container view-grid"> <thead> <tr> <th id='headerName' class="hidden column-name"> diff --git a/apps/files_sharing/css/public.scss b/apps/files_sharing/css/public.scss index 1423705ffc9..44b7e53d207 100644 --- a/apps/files_sharing/css/public.scss +++ b/apps/files_sharing/css/public.scss @@ -1,5 +1,4 @@ #preview { - background: var(--color-main-background); text-align: center; } diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index 2b7cea8d0dc..1dd9f5af6c7 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -229,10 +229,10 @@ OCA.Sharing.PublicApp = { this.fileList.generatePreviewUrl = function (urlSpec) { urlSpec = urlSpec || {}; if (!urlSpec.x) { - urlSpec.x = 32; + urlSpec.x = this.$table.data('preview-x') || 32; } if (!urlSpec.y) { - urlSpec.y = 32; + urlSpec.y = this.$table.data('preview-y') || 32; } urlSpec.x *= window.devicePixelRatio; urlSpec.y *= window.devicePixelRatio; diff --git a/apps/files_sharing/lib/Controller/ShareController.php b/apps/files_sharing/lib/Controller/ShareController.php index 409762482db..1e3cbb51028 100644 --- a/apps/files_sharing/lib/Controller/ShareController.php +++ b/apps/files_sharing/lib/Controller/ShareController.php @@ -357,6 +357,7 @@ class ShareController extends AuthPublicShareController { $folder->assign('isPublic', true); $folder->assign('hideFileList', $hideFileList); $folder->assign('publicUploadEnabled', 'no'); + $folder->assign('showgridview', true); $folder->assign('uploadMaxFilesize', $maxUploadFilesize); $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize)); $folder->assign('freeSpace', $freeSpace); diff --git a/apps/files_sharing/templates/list.php b/apps/files_sharing/templates/list.php index ec13b5c1f77..de92037a563 100644 --- a/apps/files_sharing/templates/list.php +++ b/apps/files_sharing/templates/list.php @@ -10,7 +10,7 @@ <h2><?php p($l->t('No entries found in this folder')); ?></h2> </div> -<table id="filestable"> +<table id="filestable" class="list-container view-grid"> <thead> <tr> <th id='headerName' class="hidden column-name"> diff --git a/apps/files_sharing/tests/js/publicAppSpec.js b/apps/files_sharing/tests/js/publicAppSpec.js index dc9000af152..9d24a7a7946 100644 --- a/apps/files_sharing/tests/js/publicAppSpec.js +++ b/apps/files_sharing/tests/js/publicAppSpec.js @@ -60,7 +60,7 @@ describe('OCA.Sharing.PublicApp tests', function() { '<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' + // dummy table // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead><tr>' + '<th id="headerName" class="hidden column-name">' + '<input type="checkbox" id="select_all_files" class="select-all">' + diff --git a/apps/files_sharing/tests/js/shareSpec.js b/apps/files_sharing/tests/js/shareSpec.js index 554a3a82b34..39472fdeedb 100644 --- a/apps/files_sharing/tests/js/shareSpec.js +++ b/apps/files_sharing/tests/js/shareSpec.js @@ -28,7 +28,7 @@ describe('OCA.Sharing.Util tests', function() { // dummy file list var $div = $( '<div id="listContainer">' + - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead></thead>' + '<tbody id="fileList"></tbody>' + '</table>' + @@ -510,8 +510,8 @@ describe('OCA.Sharing.Util tests', function() { OCA.Sharing.Util.attach(fileList); fileList.setFiles(testFiles); }); - afterEach(function() { - shareTabSpy.restore(); + afterEach(function() { + shareTabSpy.restore(); }); it('updates fileInfoModel when shares changed', function() { diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js index c9e2bafcc23..b0b7c1b9b99 100644 --- a/apps/files_sharing/tests/js/sharedfilelistSpec.js +++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js @@ -28,7 +28,7 @@ describe('OCA.Sharing.FileList tests', function() { '</div>' + // dummy table // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead><tr>' + '<th id="headerName" class="hidden column-name">' + '<input type="checkbox" id="select_all_files" class="select-all">' + @@ -701,7 +701,7 @@ describe('OCA.Sharing.FileList tests', function() { // dummy file list var $div = $( '<div>' + - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead></thead>' + '<tbody id="fileList"></tbody>' + '</table>' + diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index dd24abb5de1..054ffee6176 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -18,7 +18,7 @@ <p></p> </div> -<table id="filestable"> +<table id="filestable" class="list-container view-grid"> <thead> <tr> <th id="headerSelection" class="hidden column-selection"> diff --git a/apps/files_trashbin/tests/js/filelistSpec.js b/apps/files_trashbin/tests/js/filelistSpec.js index e650a2f2d28..a56ee987b78 100644 --- a/apps/files_trashbin/tests/js/filelistSpec.js +++ b/apps/files_trashbin/tests/js/filelistSpec.js @@ -48,7 +48,7 @@ describe('OCA.Trashbin.FileList tests', function () { '</div>' + // dummy table // TODO: at some point this will be rendered by the fileList class itself! - '<table id="filestable">' + + '<table id="filestable" class="list-container view-grid">' + '<thead><tr><th id="headerName" class="hidden">' + '<input type="checkbox" id="select_all_trash" class="select-all">' + '<span class="name">Name</span>' + diff --git a/core/css/css-variables.scss b/core/css/css-variables.scss index 2f3e8aa648c..a2946672294 100644 --- a/core/css/css-variables.scss +++ b/core/css/css-variables.scss @@ -5,6 +5,7 @@ :root { --color-main-text: $color-main-text; --color-main-background: $color-main-background; + --color-main-background-translucent: $color-main-background-translucent; --color-background-dark: $color-background-dark; --color-background-darker: $color-background-darker; diff --git a/core/css/icons.scss b/core/css/icons.scss index ca2a179d48f..5b96d1223a7 100644 --- a/core/css/icons.scss +++ b/core/css/icons.scss @@ -297,6 +297,7 @@ img, object, video, button, textarea, input, select, div[contenteditable='true'] @include icon-black-white('toggle', 'actions', 1, true); @include icon-black-white('toggle-background', 'actions', 1, true); @include icon-black-white('toggle-pictures', 'actions', 1, true); +@include icon-black-white('toggle-filelist', 'actions', 1, true); @include icon-black-white('triangle-e', 'actions', 1, true); @include icon-black-white('triangle-n', 'actions', 1, true); @include icon-black-white('triangle-s', 'actions', 1, true); diff --git a/core/css/styles.scss b/core/css/styles.scss index 6f65f00df19..5f68a0d08e0 100644 --- a/core/css/styles.scss +++ b/core/css/styles.scss @@ -167,7 +167,7 @@ body { height: 44px; padding: 0; margin: 0; - background-color: var(--color-main-background); + background-color: var(--color-main-background-translucent); z-index: 60; -webkit-user-select: none; -moz-user-select: none; @@ -697,12 +697,15 @@ code { } /* ---- DIALOGS ---- */ - #oc-dialog-filepicker-content { + position: relative; + .dirtree { - width: 96%; + width: 100%; flex-wrap: wrap; padding-left: 12px; + padding-right: 44px; + box-sizing: border-box; div:first-child a { background-image: url('../img/places/home.svg?v=1'); @@ -722,6 +725,28 @@ code { } } } + + /* Grid view toggle */ + #picker-view-toggle { + position: absolute; + background-color: transparent; + border: none; + margin: 0; + padding: 22px; + opacity: .5; + right: 0; + top: 0; + + &:hover, + &:focus { + opacity: 1; + } + } + // keyboard focus + #picker-showgridview:focus + #picker-view-toggle { + opacity: 1; + } + .filelist-container { box-sizing: border-box; display: inline-block; @@ -771,9 +796,54 @@ code { .filesize { text-align: right; } + &.view-grid { + $grid-size: 120px; + $grid-pad: 10px; + $name-height: 20px; + display: flex; + flex-direction: column; + + tbody { + display: grid; + grid-template-columns: repeat(auto-fill, $grid-size); + justify-content: space-around; + row-gap: 15px; + margin: 15px 0; + + tr { + display: block; + position: relative; + border-radius: var(--border-radius); + padding: $grid-pad; + display: flex; + flex-direction: column; + width: $grid-size - 2 * $grid-pad; + + td { + border: none; + padding: 0; + + &.filename { + padding: #{$grid-size - 2 * $grid-pad} 0 0 0; + background-position: center top; + background-size: contain; + line-height: $name-height; + height: $name-height; + } + &.filesize { + line-height: $name-height; + text-align: left; + } + &.date { + display: none; + } + } + } + } + } } .filepicker_element_selected { - background-color: lightblue; + background-color: var(--color-background-darker); } } diff --git a/core/css/variables.scss b/core/css/variables.scss index 5a25f07bc34..dffd6403471 100644 --- a/core/css/variables.scss +++ b/core/css/variables.scss @@ -33,6 +33,7 @@ // DEPRECATED, please use CSS4 vars $color-main-text: #222 !default; // Not #000 for better readability $color-main-background: #fff !default; +$color-main-background-translucent: rgba($color-main-background, .97) !default; // used for different active/disabled states $color-background-dark: nc-darken($color-main-background, 7%) !default; diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index 7369298b8d5..5231a94f333 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -208,6 +208,7 @@ var OCdialogs = { this.filepicker.loading = true; this.filepicker.filesClient = (OCA.Sharing && OCA.Sharing.PublicApp && OCA.Sharing.PublicApp.fileList)? OCA.Sharing.PublicApp.fileList.filesClient: OC.Files.getClient(); + $.when(this._getFilePickerTemplate()).then(function($tmpl) { self.filepicker.loading = false; var dialogName = 'oc-dialog-filepicker-content'; @@ -237,6 +238,11 @@ var OCdialogs = { $('body').append(self.$filePicker); + self.$showGridView = $('input#picker-showgridview'); + self.$showGridView.on('change', _.bind(self._onGridviewChange, self)); + + self._getGridSettings(); + self.$filePicker.ready(function() { self.$filelist = self.$filePicker.find('.filelist tbody'); self.$dirTree = self.$filePicker.find('.dirtree'); @@ -779,6 +785,31 @@ var OCdialogs = { //} return dialogDeferred.promise(); }, + // get the gridview setting and set the input accordingly + _getGridSettings: function() { + var self = this; + $.get(OC.generateUrl('/apps/files/api/v1/showgridview'), function(response) { + self.$showGridView.checked = response.gridview; + self.$showGridView.next('#picker-view-toggle') + .removeClass('icon-toggle-filelist icon-toggle-pictures') + .addClass(response.gridview ? 'icon-toggle-filelist' : 'icon-toggle-pictures') + $('.list-container').toggleClass('view-grid', response.gridview); + }); + }, + _onGridviewChange: function() { + var show = this.$showGridView.is(':checked'); + // only save state if user is logged in + if (OC.currentUser) { + $.post(OC.generateUrl('/apps/files/api/v1/showgridview'), { + show: show + }); + } + this.$showGridView.next('#picker-view-toggle') + .removeClass('icon-toggle-filelist icon-toggle-pictures') + .addClass(show ? 'icon-toggle-filelist' : 'icon-toggle-pictures') + + $('.list-container').toggleClass('view-grid', show); + }, _getFilePickerTemplate: function() { var defer = $.Deferred(); if(!this.$filePickerTemplate) { @@ -899,6 +930,8 @@ var OCdialogs = { if (entry.type === 'file') { var urlSpec = { file: dir + '/' + entry.name, + x: 100, + y: 100 }; var img = new Image(); var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec); diff --git a/core/templates/filepicker.html b/core/templates/filepicker.html index 215311348cb..4c66dfc707b 100644 --- a/core/templates/filepicker.html +++ b/core/templates/filepicker.html @@ -1,11 +1,13 @@ <div id="{dialog_name}" title="{title}"> <span class="dirtree breadcrumb"></span> + <input type="checkbox" class="hidden-visually" id="picker-showgridview" checked="checked" /> + <label id="picker-view-toggle" for="picker-showgridview" class="button icon-toggle-filelist"></label> <div class="filelist-container"> <div class="emptycontent"> <div class="icon-folder"></div> <h2>{emptytext}</h2> </div> - <table id="filestable" class="filelist"> + <table id="filestable" class="filelist list-container view-grid"> <tbody> <tr data-entryname="{filename}" data-type="{type}"> <td class="filename" |