mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-21 01:13:37 +08:00
Add recent projects and tabs into Action Control
This commit is contained in:
parent
223aaad47a
commit
796f2904d9
@ -1126,7 +1126,8 @@
|
||||
color: var(--color-text);
|
||||
height: auto;
|
||||
padding: 5px;
|
||||
font-size: 0.94em
|
||||
font-size: 0.94em;
|
||||
word-break: break-word;
|
||||
}
|
||||
#action_selector ul > li {
|
||||
height: 30px;
|
||||
|
@ -429,11 +429,18 @@
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-left: 4px;
|
||||
background: var(--color-frame);
|
||||
}
|
||||
#tab_bar #tab_bar_list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-right: auto;
|
||||
}
|
||||
#tab_bar .project_tab {
|
||||
background-color: var(--color-back);
|
||||
cursor: pointer;
|
||||
@ -515,10 +522,22 @@
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
padding-top: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#new_tab_button:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
#search_tab_button {
|
||||
height: 100%;
|
||||
width: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
padding-top: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#search_tab_button:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
#tab_bar .project_tab > label.project_tab_session_badge {
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
|
51
index.html
51
index.html
@ -358,31 +358,36 @@
|
||||
<div id="blackout"></div>
|
||||
|
||||
<div id="tab_bar" :class="{drag_mode: drag_target_index !== null}">
|
||||
<div
|
||||
class="project_tab"
|
||||
v-for="(project, index) in tabs" :key="project.uuid"
|
||||
:class="{
|
||||
selected: project.selected,
|
||||
new_tab: project.is_new_tab,
|
||||
dragging: index == drag_target_index,
|
||||
move_back: (drag_position_index !== null && index > drag_target_index && drag_position_index >= index),
|
||||
move_forth: (drag_position_index !== null && index < drag_target_index && drag_position_index <= index)
|
||||
}"
|
||||
:title="project.name || project.geometry_name"
|
||||
@dblclick="project.openSettings()"
|
||||
@mousedown="mouseDown(project, $event)"
|
||||
@mouseup="mouseUp(project, $event)"
|
||||
@mouseenter="mouseEnter(project, $event)"
|
||||
@mouseleave="mouseLeave(project, $event)"
|
||||
>
|
||||
<label class="project_tab_session_badge" v-if="project.EditSession"><i class="material-icons">group</i>{{ project.EditSession.client_count }}</label>
|
||||
<label>{{ project.name || project.geometry_name || project.format.name }}</label>
|
||||
<div class="project_tab_close_button" :class="{unsaved: !project.saved}" :title="close_tab_label" @click="project.close()">
|
||||
<i class="material-icons">{{ project.saved ? 'clear' : 'fiber_manual_record' }}</i>
|
||||
<div id="tab_bar_list">
|
||||
<div
|
||||
class="project_tab"
|
||||
v-for="(project, index) in tabs" :key="project.uuid"
|
||||
:class="{
|
||||
selected: project.selected,
|
||||
new_tab: project.is_new_tab,
|
||||
dragging: index == drag_target_index,
|
||||
move_back: (drag_position_index !== null && index > drag_target_index && drag_position_index >= index),
|
||||
move_forth: (drag_position_index !== null && index < drag_target_index && drag_position_index <= index)
|
||||
}"
|
||||
:title="project.name || project.geometry_name"
|
||||
@dblclick="project.openSettings()"
|
||||
@mousedown="mouseDown(project, $event)"
|
||||
@mouseup="mouseUp(project, $event)"
|
||||
@mouseenter="mouseEnter(project, $event)"
|
||||
@mouseleave="mouseLeave(project, $event)"
|
||||
>
|
||||
<label class="project_tab_session_badge" v-if="project.EditSession"><i class="material-icons">group</i>{{ project.EditSession.client_count }}</label>
|
||||
<label>{{ project.name || project.geometry_name || project.format.name }}</label>
|
||||
<div class="project_tab_close_button" :class="{unsaved: !project.saved}" :title="close_tab_label" @click="project.close()">
|
||||
<i class="material-icons">{{ project.saved ? 'clear' : 'fiber_manual_record' }}</i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="new_tab_button" v-if="!new_tab.visible" @click="openNewTab()" :title="new_tab.name">
|
||||
<i class="material-icons">add</i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="new_tab_button" v-if="!new_tab.visible" @click="openNewTab()" :title="new_tab.name">
|
||||
<i class="material-icons">add</i>
|
||||
<div id="search_tab_button" @click="searchTabs()" :title="search_tabs_label">
|
||||
<i class="material-icons">search</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -2226,33 +2226,82 @@ const BARS = {
|
||||
length: 0,
|
||||
list: []
|
||||
},
|
||||
computed: {
|
||||
actions() {
|
||||
methods: {
|
||||
updateSearch() {
|
||||
var search_input = this._data.search_input.toUpperCase()
|
||||
var list = this._data.list.empty()
|
||||
for (var i = 0; i < Keybinds.actions.length; i++) {
|
||||
var item = Keybinds.actions[i];
|
||||
if (
|
||||
search_input.length == 0 ||
|
||||
item.name.toUpperCase().includes(search_input) ||
|
||||
item.id.toUpperCase().includes(search_input)
|
||||
) {
|
||||
if (item instanceof Action && Condition(item.condition)) {
|
||||
list.push(item)
|
||||
if (list.length > ActionControl.max_length) break;
|
||||
var type;
|
||||
if (search_input.includes(':')) {
|
||||
[type, search_input] = search_input.split(/:\s*(.*)/);
|
||||
search_input = search_input || '';
|
||||
}
|
||||
var list = this._data.list.empty();
|
||||
if (!type) {
|
||||
for (var i = 0; i < Keybinds.actions.length; i++) {
|
||||
var item = Keybinds.actions[i];
|
||||
if (
|
||||
search_input.length == 0 ||
|
||||
item.name.toUpperCase().includes(search_input) ||
|
||||
item.id.toUpperCase().includes(search_input)
|
||||
) {
|
||||
if (item instanceof Action && Condition(item.condition)) {
|
||||
list.push(item)
|
||||
if (list.length > ActionControl.max_length) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list.length <= ActionControl.max_length) {
|
||||
for (let key in settings) {
|
||||
let setting = settings[key];
|
||||
if (
|
||||
search_input.length == 0 ||
|
||||
setting.name.toUpperCase().includes(search_input) ||
|
||||
key.toUpperCase().includes(search_input)
|
||||
) {
|
||||
if (Condition(setting.condition)) {
|
||||
list.push(setting)
|
||||
if (!type || type == 'SETTINGS') {
|
||||
if (list.length <= ActionControl.max_length) {
|
||||
for (let key in settings) {
|
||||
let setting = settings[key];
|
||||
if (
|
||||
search_input.length == 0 ||
|
||||
setting.name.toUpperCase().includes(search_input) ||
|
||||
key.toUpperCase().includes(search_input)
|
||||
) {
|
||||
if (Condition(setting.condition)) {
|
||||
list.push(setting)
|
||||
if (list.length > ActionControl.max_length) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isApp && type == 'RECENT') {
|
||||
if (list.length <= ActionControl.max_length) {
|
||||
for (let project of recent_projects) {
|
||||
if (
|
||||
search_input.length == 0 ||
|
||||
project.path.toUpperCase().includes(search_input)
|
||||
) {
|
||||
list.push({
|
||||
name: project.name,
|
||||
icon: project.icon,
|
||||
description: project.path,
|
||||
keybind_label: StartScreen.vue.getDate(project),
|
||||
type: 'recent_project'
|
||||
})
|
||||
if (list.length > ActionControl.max_length) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isApp && type == 'TAB') {
|
||||
if (list.length <= ActionControl.max_length) {
|
||||
for (let project of ModelProject.all) {
|
||||
if (
|
||||
search_input.length == 0 ||
|
||||
project.name.toUpperCase().includes(search_input) ||
|
||||
project.geometry_name.toUpperCase().includes(search_input)
|
||||
) {
|
||||
list.push({
|
||||
name: project.name,
|
||||
icon: project.format.icon,
|
||||
description: project.path,
|
||||
keybind_label: Modes.options[project.mode].name,
|
||||
uuid: project.uuid,
|
||||
type: 'project_tab'
|
||||
})
|
||||
if (list.length > ActionControl.max_length) break;
|
||||
}
|
||||
}
|
||||
@ -2266,11 +2315,9 @@ const BARS = {
|
||||
this._data.index = list.length-1;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
subtext() {
|
||||
let action = this.actions[this.index];
|
||||
let action = this.list[this.index];
|
||||
if (Pressing.alt) {
|
||||
if (action instanceof Setting) {
|
||||
if (action.type == 'select') {
|
||||
@ -2286,20 +2333,29 @@ const BARS = {
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
search_input() {
|
||||
this.updateSearch();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<dialog id="action_selector" v-if="open">
|
||||
<input type="text" v-model="search_input" @input="e => search_input = e.target.value" autocomplete="off" autosave="off" autocorrect="off" spellcheck="off" autocapitalize="off">
|
||||
<i class="material-icons" id="action_search_bar_icon">search</i>
|
||||
<div id="action_selector_list">
|
||||
<ul>
|
||||
<li v-for="(item, i) in actions"
|
||||
v-html="item.menu_node.innerHTML"
|
||||
<li v-for="(item, i) in list"
|
||||
:class="{selected: i === index}"
|
||||
:title="item.description"
|
||||
@click="ActionControl.click(item, $event)"
|
||||
@mouseenter="index = i"
|
||||
></li>
|
||||
>
|
||||
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
|
||||
<span>{{ item.name }}</span>
|
||||
<label class="keybinding_label">{{ item.keybind_label || (item.keybind ? item.keybind.label : '') }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="small_text" v-if="actions[index]">{{ subtext() }}</div>
|
||||
<div class="small_text" v-if="list[index]">{{ subtext() }}</div>
|
||||
</div>
|
||||
</dialog>
|
||||
`
|
||||
@ -2325,19 +2381,24 @@ const ActionControl = {
|
||||
set open(state) {ActionControl.vue._data.open = !!state},
|
||||
type: 'action_selector',
|
||||
max_length: 32,
|
||||
select() {
|
||||
select(input) {
|
||||
ActionControl.open = true;
|
||||
open_interface = ActionControl;
|
||||
ActionControl.vue._data.index = 0;
|
||||
ActionControl.vue.updateSearch();
|
||||
if (input) {
|
||||
ActionControl.vue.search_input = input;
|
||||
}
|
||||
Vue.nextTick(_ => {
|
||||
$('#action_selector > input').focus().select();
|
||||
let element = $('#action_selector > input');
|
||||
element.trigger('focus');
|
||||
if (!input) element.trigger('select');
|
||||
})
|
||||
|
||||
// Update settings icons. Might need to be moved
|
||||
for (let key in settings) {
|
||||
let setting = settings[key];
|
||||
if (setting.type == 'toggle') {
|
||||
setting.menu_node.children[0].innerText = setting.value ? 'check_box' : 'check_box_outline_blank';
|
||||
setting.icon = setting.value ? 'check_box' : 'check_box_outline_blank';
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2361,7 +2422,15 @@ const ActionControl = {
|
||||
$('body').effect('shake');
|
||||
Blockbench.showQuickMessage('Congratulations! You have discovered recursion!', 3000)
|
||||
}
|
||||
action.trigger(e);
|
||||
if (action.type == 'recent_project') {
|
||||
Blockbench.read([action.description], {}, files => {
|
||||
loadModelFile(files[0]);
|
||||
})
|
||||
} else if (action.type == 'project_tab') {
|
||||
ModelProject.all.find(p => p.uuid == action.uuid).select();
|
||||
} else {
|
||||
action.trigger(e);
|
||||
}
|
||||
},
|
||||
click(action, e) {
|
||||
ActionControl.trigger(action, e)
|
||||
|
@ -58,29 +58,15 @@ class Setting {
|
||||
})
|
||||
}
|
||||
|
||||
// Menu node for action control
|
||||
this.menu_node = document.createElement('li');
|
||||
|
||||
var icon = this.icon;
|
||||
if (!icon) {
|
||||
if (this.type == 'toggle') icon = this.value ? 'check_box' : 'check_box_outline_blank';
|
||||
if (this.type == 'number') icon = 'tag';
|
||||
if (this.type == 'password') icon = 'password';
|
||||
if (this.type == 'text') icon = 'format_color_text';
|
||||
if (this.type == 'select') icon = 'list';
|
||||
if (!icon) icon = 'settings';
|
||||
if (!this.icon) {
|
||||
if (this.type == 'toggle') this.icon = this.value ? 'check_box' : 'check_box_outline_blank';
|
||||
if (this.type == 'number') this.icon = 'tag';
|
||||
if (this.type == 'password') this.icon = 'password';
|
||||
if (this.type == 'text') this.icon = 'format_color_text';
|
||||
if (this.type == 'select') this.icon = 'list';
|
||||
if (!this.icon) this.icon = 'settings';
|
||||
}
|
||||
let icon_node = Blockbench.getIconNode(icon);
|
||||
this.menu_node.append(icon_node);
|
||||
|
||||
let span = document.createElement('span');
|
||||
span.innerText = this.name;
|
||||
this.menu_node.append(span);
|
||||
|
||||
let label = document.createElement('label');
|
||||
label.innerText = tl('data.setting');
|
||||
label.className = 'keybinding_label';
|
||||
this.menu_node.append(label);
|
||||
this.keybind_label = tl('data.setting');
|
||||
}
|
||||
delete() {
|
||||
if (settings[this.id]) {
|
||||
|
@ -415,6 +415,7 @@ onVueSetup(() => {
|
||||
drag_target_index: null,
|
||||
drag_position_index: null,
|
||||
close_tab_label: tl('projects.close_tab'),
|
||||
search_tabs_label: tl('generic.search'),
|
||||
new_tab: {
|
||||
name: tl('projects.new_tab'),
|
||||
saved: true,
|
||||
@ -451,13 +452,18 @@ onVueSetup(() => {
|
||||
this.new_tab.select();
|
||||
setStartScreen(true);
|
||||
},
|
||||
searchTabs() {
|
||||
ActionControl.select('tab:');
|
||||
},
|
||||
mouseDown(tab, e1) {
|
||||
convertTouchEvent(e1);
|
||||
e1.preventDefault();
|
||||
|
||||
if (this.thumbnail) {
|
||||
this.thumbnail.remove();
|
||||
delete this.thumbnail;
|
||||
}
|
||||
if (e1.button == 1) return;
|
||||
|
||||
let scope = this;
|
||||
let active = false;
|
||||
@ -564,10 +570,10 @@ onVueSetup(() => {
|
||||
mouseLeave() {
|
||||
if (this.thumbnail) {
|
||||
this.thumbnail_timeout = setTimeout(() => {
|
||||
this.thumbnail.remove();
|
||||
if (this.thumbnail) this.thumbnail.remove();
|
||||
delete this.thumbnail;
|
||||
delete this.thumbnail_timeout;
|
||||
}, 40)
|
||||
}, 80)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user