Skip to content

Commit 315812c

Browse files
committed
WIP: contextual actions on file/folder.
Signed-off-by: ubi de feo <me@ubidefeo.com>
1 parent 9012af9 commit 315812c

File tree

3 files changed

+70
-29
lines changed

3 files changed

+70
-29
lines changed

ui/arduino/main.css

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ button.small .icon {
638638
height: 28px;
639639
min-height: 28px;
640640
max-height: 28px;;
641-
padding: 5px 10px;
641+
padding: 5px 0;
642642
align-items: center;
643643
gap: 10px;
644644
align-self: stretch;
@@ -657,14 +657,27 @@ button.small .icon {
657657
align-items: center;
658658
align-self: stretch;
659659
cursor: pointer;
660-
width: 22px;
661660
transition: all 0.1s;
662661
}
663662

664663
.file-list .item:hover .options {
665664
opacity: 1;
666665
}
667666

667+
.file-list .item.selected.actionable .options {
668+
opacity: 0;
669+
}
670+
671+
.file-list .item .checkbox {
672+
display: none;
673+
}
674+
.file-list .item.actionable .checkbox {
675+
display: flex;
676+
}
677+
.file-list .item.selected.actionable .checkbox {
678+
display: none;
679+
}
680+
668681
.file-list .item .icon {
669682
width: 32px;
670683
height: 32px;
@@ -715,18 +728,18 @@ button.small .icon {
715728
}
716729

717730
.popup-menu {
718-
position: absolute;
731+
/* position: absolute;
719732
top: auto;
720-
bottom: auto;
721-
background: white;
722-
border: 1px solid #ddd;
733+
bottom: auto; */
734+
/* background: white;
735+
border: 1px solid #ddd; */
723736
border-radius: 8px;
724737
display: flex;
725738
z-index: 1000;
726739
gap: 4px;
727740
align-items: stretch;
728741
height: 28px;
729-
padding: 4px 4px;
742+
padding: 0px 4px;
730743
margin: 0;
731744
flex-direction: row;
732745
right: 0px;

ui/arduino/store.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async function store(state, emitter) {
3030
win.setWindowSize(720, 640)
3131

3232
state.platform = window.BridgeWindow.getOS()
33-
state.view = 'editor'
33+
state.view = 'file-manager'
3434
state.diskNavigationPath = '/'
3535
state.diskNavigationRoot = getDiskNavigationRootFromStorage()
3636
state.diskFiles = []
@@ -39,7 +39,7 @@ async function store(state, emitter) {
3939
state.boardFiles = []
4040
state.openFiles = []
4141
state.selectedFiles = []
42-
state.fileContextMenu = null
42+
state.itemActionMenu = null
4343

4444
state.newTabFileName = null
4545
state.editingFile = null
@@ -1138,7 +1138,7 @@ async function store(state, emitter) {
11381138
})
11391139

11401140
emitter.on('file-context-menu', (file, source, event) => {
1141-
state.selectedFiles = []
1141+
// state.selectedFiles = []
11421142
let parentFolder = source == 'board' ? state.boardNavigationPath : state.diskNavigationPath
11431143
log('file-contextual-menu', file, source, event)
11441144
const isSelected = state.selectedFiles.find((f) => {
@@ -1156,13 +1156,14 @@ async function store(state, emitter) {
11561156
parentFolder: parentFolder
11571157
})
11581158
}
1159-
state.fileContextMenu = state.selectedFiles[state.selectedFiles.length - 1]
1159+
state.itemActionMenu = state.selectedFiles[state.selectedFiles.length - 1]
11601160
emitter.emit('render')
11611161
})
11621162

11631163
emitter.on('toggle-file-selection', (file, source, event) => {
11641164
log('toggle-file-selection', file, source, event)
11651165
let parentFolder = source == 'board' ? state.boardNavigationPath : state.diskNavigationPath
1166+
11661167
// Single file selection unless holding keyboard key
11671168
if (event && !event.ctrlKey && !event.metaKey) {
11681169
state.selectedFiles = [{
@@ -1171,7 +1172,9 @@ async function store(state, emitter) {
11711172
source: source,
11721173
parentFolder: parentFolder
11731174
}]
1175+
state.itemActionMenu = null
11741176
emitter.emit('render')
1177+
console.log(state.selectedFiles)
11751178
return
11761179
}
11771180

@@ -1190,6 +1193,7 @@ async function store(state, emitter) {
11901193
parentFolder: parentFolder
11911194
})
11921195
}
1196+
console.log(state.selectedFiles)
11931197
emitter.emit('render')
11941198
})
11951199
emitter.on('open-selected-files', async () => {

ui/arduino/views/components/file-list.js

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
const DiskFileList = generateFileList('disk')
22
const BoardFileList = generateFileList('board')
33

4-
function generateFileList(source) {
4+
function generateFileList(source, selectedFiles) {
5+
56
return function FileList(state, emit) {
67
function onKeyEvent(e) {
78
if(e.key.toLowerCase() === 'enter') {
@@ -13,6 +14,8 @@ function generateFileList(source) {
1314
}
1415
}
1516

17+
/* template for new file item, with focussed input
18+
ESC to cancel, ENTER to finish */
1619
const newFileItem = html`
1720
<div class="item">
1821
<img class="icon" src="media/file.svg" />
@@ -26,6 +29,8 @@ function generateFileList(source) {
2629
</div>
2730
</div>
2831
`
32+
/* template for new folder item, with focussed input
33+
ESC to cancel, ENTER to finish */
2934
const newFolderItem = html`
3035
<div class="item">
3136
<img class="icon" src="media/folder.svg" />
@@ -39,22 +44,23 @@ function generateFileList(source) {
3944
</div>
4045
</div>
4146
`
47+
4248
function dismissContextMenu(e, item) {
4349
console.log("click action", e, item)
4450
e.stopPropagation()
45-
state.fileContextMenu = null
51+
state.itemActionMenu = null
4652
state.selectedFiles = []
4753
emit('render')
4854
}
4955
function triggerRemove() {
5056
emit('remove-files')
51-
state.fileContextMenu = null
57+
state.itemActionMenu = null
5258
emit('render')
5359
}
5460
function triggerRename(item) {
5561
emit('rename-file', source, item)
5662

57-
state.fileContextMenu = null
63+
state.itemActionMenu = null
5864
emit('render')
5965
}
6066
function triggerTransfer() {
@@ -63,10 +69,11 @@ function generateFileList(source) {
6369
}else{
6470
emit('download-files')
6571
}
66-
state.fileContextMenu = null
72+
state.itemActionMenu = null
6773
emit('render')
6874
}
69-
function FileOptions(item, i){
75+
76+
function ItemActions(item, i){
7077
const popupMenu = html`
7178
<div class="popup-menu">
7279
<div class="popup-menu-item ${state.isConnected ? '' : 'disabled'}" onclick=${triggerTransfer}><img src="media/${source === 'disk' ? 'upload' : 'download'}.svg" /></div>
@@ -91,7 +98,6 @@ function generateFileList(source) {
9198
f => f.fileName === item.fileName && f.source === source
9299
)
93100

94-
const hasContextMenu = state.fileContextMenu && state.fileContextMenu.fileName === item.fileName && state.fileContextMenu.source === source
95101
function renameItem(e) {
96102
e.preventDefault()
97103
emit('rename-file', source, item)
@@ -104,54 +110,72 @@ function generateFileList(source) {
104110
if (!state.renamingFile) emit(`open-file`, source, item)
105111
}
106112

107-
function toggleContextMenu(item, source, e) {
113+
function toggleActionsMenu(item, source, e) {
108114
e.stopPropagation()
109115
console.log("show file options", item, source, e)
110116
// const popupMenu = e.currentTarget.parentElement.querySelector('.popup-menu')
111117
// popupMenu.classList.add('visible')
112118
emit('file-context-menu', item, source, e)
113119
}
120+
121+
function checkboxToggle(item, source, e) {
122+
e.stopPropagation()
123+
emit('toggle-file-selection', item, source, e)
124+
}
125+
114126
let fileName = item.fileName
115127
const isSelected = state.selectedFiles.find(f => f.fileName === fileName)
116128

117129
if (state.renamingFile == source && isSelected) {
118130
fileName = renamingFileItem
119131
}
120132

121-
contextMenuHtml = html``
122-
if (hasContextMenu) {
123-
contextMenuHtml = html`${FileOptions(item, i)}`
124-
}
133+
// a context menu has been triggered
134+
const contextMenuOpen = state.itemActionMenu != null
135+
136+
// only show the action menu on current item
137+
const showActionMenu = state.itemActionMenu && state.itemActionMenu.fileName === item.fileName && state.itemActionMenu.source === source
138+
139+
// let actionMenuHtml = html``
140+
// if (showActionMenu) {
141+
const actionMenuHtml = showActionMenu ? html`${ItemActions(item, i)}` : html``
142+
// }
125143

126144
if (item.type === 'folder') {
127145
return html`
128146
<div
129-
class="item ${isChecked ? 'selected' : ''}"
147+
class="item ${isChecked ? 'selected' : ''} ${showActionMenu ? 'actionable' : ''}"
130148
onclick=${(e) => emit('toggle-file-selection', item, source, e)}
131149
ondblclick=${navigateToFolder}
132150
>
133151
<img class="icon" src="media/folder.svg" />
134152
<div class="text">${fileName}</div>
135-
<div class="options" onclick=${(e) => toggleContextMenu(item, source, e)}>}>
153+
<div class="options" onclick=${(e) => toggleActionsMenu(item, source, e)}>}>
136154
<img src="media/more.svg" />
137155
</div>
138-
${contextMenuHtml}
156+
<div class="checkbox" onclick=${(e) => checkboxToggle(item, source, e)}>}>
157+
<img src="media/unchecked.svg" />
158+
</div>
159+
${actionMenuHtml}
139160
</div>
140161
`
141162
} else {
142163
//<div class="options" onclick=${(e) => {contextualMenu(e, item)}}>
143164
return html`
144165
<div
145-
class="item ${isChecked ? 'selected' : ''}"
166+
class="item ${isChecked ? 'selected' : ''} ${showActionMenu ? 'actionable' : ''}"
146167
onclick=${(e) => emit('toggle-file-selection', item, source, e)}
147168
ondblclick=${openFile}
148169
>
149170
<img class="icon" src="media/file.svg" />
150171
<div class="text">${fileName}</div>
151-
<div class="options" onclick=${(e) => toggleContextMenu(item, source, e)}>
172+
<div class="options" onclick=${(e) => toggleActionsMenu(item, source, e)}>
152173
<img src="media/more.svg" />
153174
</div>
154-
${contextMenuHtml}
175+
<div class="checkbox" onclick=${(e) => checkboxToggle(item, source, e)}>}>
176+
<img src="media/unchecked.svg" />
177+
</div>
178+
${actionMenuHtml}
155179
</div>
156180
`
157181
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy