const StartScreen = { loaders: {}, open() { Interface.tab_bar.openNewTab(); } }; function addStartScreenSection(id, data) { if (typeof id == 'object') { data = id; id = ''; } var obj = $(Interface.createElement('section', {id})) if (typeof data.graphic === 'object') { var left = $('
') obj.append(left) if (data.graphic.type === 'icon') { var icon = Blockbench.getIconNode(data.graphic.icon) left.addClass('graphic_icon') left.append(icon) } else { left.css('background-image', `url('${data.graphic.source}')`) } if (data.graphic.width) { left.css('width', data.graphic.width+'px'); } if (data.graphic.width && data.text) { left.css('flex-shrink', '0'); } if (data.graphic.width && data.graphic.height && Blockbench.isMobile) { left.css('height', '0') .css('padding-top', '0') .css('padding-bottom', (data.graphic.height/data.graphic.width*100)+'%') } else { if (data.graphic.height) left.css('height', data.graphic.height+'px'); if (data.graphic.width && !data.graphic.height && !data.graphic.aspect_ratio) left.css('height', data.graphic.width+'px'); if (data.graphic.aspect_ratio) left.css('aspect-ratio', data.graphic.aspect_ratio); } if (data.graphic.description) { let content = $(pureMarked(data.graphic.description)); content.addClass('start_screen_graphic_description') content.css({ 'color': data.graphic.text_color || '#ffffff', }); left.append(content); } } if (data.text instanceof Array) { var right = $('
') obj.append(right) data.text.forEach(line => { var content = line.text ? pureMarked(tl(line.text)) : ''; switch (line.type) { case 'h1': var tag = 'h1'; break; case 'h2': var tag = 'h3'; break; case 'h3': var tag = 'h4'; break; case 'list': var tag = 'ul class="list_style"'; line.list.forEach(string => { content += `
  • ${pureMarked(tl(string))}
  • `; }) break; case 'button': var tag = 'button'; break; default: var tag = 'p'; break; } var l = $(`<${tag}>${content}`); if (typeof line.click == 'function') { l.on('click', line.click); } right.append(l); }) } if (data.layout == 'vertical') { obj.addClass('vertical'); } if (data.features instanceof Array) { let features_section = document.createElement('ul'); features_section.className = 'start_screen_features' data.features.forEach(feature => { let li = document.createElement('li'); let img = new Image(); img.src = feature.image; let title = document.createElement('h3'); title.textContent = feature.title; let text = document.createElement('p'); text.textContent = feature.text; li.append(img, title, text); features_section.append(li); }) obj.append(features_section); } if (data.closable !== false) { obj.append(`clear`); obj.find('i.start_screen_close_button').click((e) => { obj.detach() }); } if (typeof data.click == 'function') { obj.on('click', event => { if (event.target.classList.contains('start_screen_close_button')) return; data.click() }) } if (data.color) { obj.css('background-color', data.color); if (data.color == 'var(--color-bright_ui)') { obj.addClass('bright_ui') } } if (data.text_color) { obj.css('color', data.text_color); } if (data.last) { $('#start_screen > content').append(obj); } else if (data.insert_after) { $('#start_screen > content').find(`#${data.insert_after}`).after(obj); } else if (data.insert_before) { $('#start_screen > content').find(`#${data.insert_before}`).before(obj); } else { $('#start_screen > content').prepend(obj); } if (!obj[0].parentElement) { $('#start_screen > content').append(obj); } return { delete() { obj[0].remove(); } } } onVueSetup(function() { StateMemory.init('start_screen_list_type', 'string') let slideshow_timer = 0; StartScreen.vue = new Vue({ el: '#start_screen', components: {}, data: { formats: Formats, loaders: ModelLoader.loaders, selected_format_id: '', viewed_format: null, recent: isApp ? recent_projects : [], list_type: StateMemory.start_screen_list_type || 'grid', redact_names: settings.streamer_mode.value, redacted: tl('generic.redacted'), search_term: '', isApp, mobile_layout: Blockbench.isMobile, thumbnails: {}, getIconNode: Blockbench.getIconNode, slideshow: [ { source: "./assets/splash_art/1.png", description: "Splash Art 1st Place by [KanekiAkira](https://twitter.com/kaneki_akira) & [Jumi](https://jumi-pf.com)", }, { source: "./assets/splash_art/2.png", description: "Splash Art 2nd Place by [PICASSO](https://twitter.com/Picasso114514) & [AnzSama](https://twitter.com/AnzSamaEr)", }, { source: "./assets/splash_art/3.png", description: "Splash Art 3rd Place by [Wanwin](https://wan-win.com/#3darts)", }, { source: "./assets/splash_art/4.png", description: "Splash Art 4th Place by [soul shadow](https://twitter.com/Ghost773748999)", }, { source: "./assets/splash_art/5.png", description: "Splash Art 5th Place by [Azagwen](https://twitter.com/azagwen) & [shroomy](https://twitter.com/ShroomyArts)", } ], show_splash_screen: (Blockbench.hasFlag('after_update') || settings.always_show_splash_art.value), slideshow_selected: 0, slideshow_last: null, slideshow_autoplay: true }, methods: { getDate(p) { if (p.day) { var diff = (365e10 + Blockbench.openTime.dayOfYear() - p.day) % 365; if (diff <= 0) { return tl('dates.today'); } else if (diff == 1) { return tl('dates.yesterday'); } else if (diff <= 7) { return tl('dates.this_week'); } else { return tl('dates.weeks_ago', [Math.ceil(diff/7)]); } } else { return '-' } }, openProject: function(p, event) { Blockbench.read([p.path], {}, files => { loadModelFile(files[0]); }) }, updateThumbnails(model_paths) { this.recent.forEach(project => { if (model_paths && !model_paths.includes(project.path)) return; let hash = project.path.hashCode().toString().replace(/^-/, '0'); let path = PathModule.join(app.getPath('userData'), 'thumbnails', `${hash}.png`); if (!fs.existsSync(path)) { delete this.thumbnails[project.path]; } else { this.thumbnails[project.path] = path + '?' + Math.round(Math.random()*255); } }) this.$forceUpdate(); }, setListType(type) { this.list_type = type; StateMemory.start_screen_list_type = type; StateMemory.save('start_screen_list_type') }, recentProjectContextMenu(recent_project, event) { let menu = new Menu('recent_project', [ { id: 'favorite', name: 'mode.start.recent.favorite', icon: recent_project.favorite ? 'fas.fa-star' : 'far.fa-star', click: () => { this.toggleProjectFavorite(recent_project); } }, { id: 'open_folder', name: 'menu.texture.folder', icon: 'folder', click() { shell.showItemInFolder(recent_project.path) } }, { id: 'remove', name: 'generic.remove', icon: 'clear', click: () => { recent_projects.remove(recent_project); updateRecentProjects(); } } ]) menu.show(event); }, toggleProjectFavorite(recent_project) { recent_project.favorite = !recent_project.favorite; if (recent_project.favorite) { recent_projects.remove(recent_project); recent_projects.splice(0, 0, recent_project); } updateRecentProjects(); }, getFormatCategories() { let categories = {}; function add(key, format) { if (!categories[format.category]) { categories[format.category] = { name: tl('format_category.' + format.category), entries: [] } } categories[format.category].entries.push(format); } for (let key in this.formats) { if (this.formats[key].show_on_start_screen != false) { add(key, this.formats[key]); } } for (let key in this.loaders) { if (this.loaders[key].show_on_start_screen != false) { add(key, this.loaders[key]); } } return categories; }, loadFormat(format_entry) { this.selected_format_id = format_entry.id; if (format_entry.onFormatPage) format_entry.onFormatPage(); Vue.nextTick(() => { let button = document.querySelector('.start_screen_format_page button'); if (!button) return; let offset = $(button).offset().top; if (offset + 38 > window.innerHeight) { let change = offset + 64 - window.innerHeight; StartScreen.vue.$el.scrollTo({top: StartScreen.vue.$el.scrollTop + change, behavior: 'smooth'}) } }) }, confirmSetupScreen(format_entry) { this.selected_format_id = ''; if (format_entry.onStart) format_entry.onStart(); if (typeof format_entry.new == 'function') format_entry.new(); }, getBackground(url) { return `url("${url}")` }, setSlide(index) { this.slideshow_last = this.slideshow_selected; this.slideshow_selected = index; setTimeout(() => this.slideshow_last = null, 500); slideshow_timer = 0; }, openLink(link) { Blockbench.openLink(link); }, pureMarked, tl }, computed: { projects() { if (!this.search_term) return this.recent; let terms = this.search_term.toLowerCase().split(/\s/); return this.recent.filter(project => { return !terms.find(term => ( !project.path.toLowerCase().includes(term) )) }) } }, mounted() { this.updateThumbnails(); setInterval(() => { if (this.show_splash_screen && this.slideshow_autoplay && this.$el.offsetParent) { slideshow_timer += 1; if (slideshow_timer == 24) { this.setSlide((this.slideshow_selected+1) % this.slideshow.length); } } }, 1000); if (settings.always_show_splash_art.value && !Blockbench.hasFlag('after_update') && !Blockbench.isMobile) { document.getElementById('start_screen').scrollTop = 100; } }, template: `

    clear

    ${tl('mode.start.new')}

      • help
      • menu_book
    clear

    {{ viewed_format.name }}

    ${tl('mode.start.recent')}

  • view_module
  • list
  • {{ '['+tl('generic.redacted')+']' }}
    • {{ redact_names ? redacted : project.name }} {{ getDate(project) }}
    • {{ tl('mode.start.no_recents') }}
    • {{ redact_names ? redacted : project.name }}
    ` }) Blockbench.on('construct_format delete_format', () => { StartScreen.vue.$forceUpdate(); }) if (settings.streamer_mode.value) { updateStreamerModeNotification() } //Backup Model if (localStorage.getItem('backup_model') && (!isApp || !currentwindow.webContents.second_instance) && localStorage.getItem('backup_model').length > 40) { var backup_models = localStorage.getItem('backup_model') let section = addStartScreenSection({ color: 'var(--color-back)', graphic: {type: 'icon', icon: 'fa-archive'}, insert_before: 'start_files', text: [ {type: 'h2', text: tl('message.recover_backup.title')}, {text: tl('message.recover_backup.message')}, {type: 'button', text: tl('message.recover_backup.recover'), click: (e) => { let parsed_backup_models = JSON.parse(backup_models); for (let uuid in parsed_backup_models) { AutoBackupModels[uuid] = parsed_backup_models[uuid]; let model = parsed_backup_models[uuid]; setupProject(Formats[model.meta.model_format] || Formats.free, uuid); Codecs.project.parse(model, 'backup.bbmodel') } section.delete(); }}, {type: 'button', text: tl('dialog.discard'), click: (e) => { localStorage.removeItem('backup_model'); section.delete(); }} ] }) } }); class ModelLoader { constructor(id, options) { this.id = id; this.name = tl(options.name); this.description = options.description ? tl(options.description) : ''; this.icon = options.icon || 'arrow_forward'; this.category = options.category || 'loaders'; this.target = options.target || ''; this.show_on_start_screen = true; this.confidential = options.confidential || false; this.condition = options.condition; this.plugin = options.plugin || (typeof Plugins != 'undefined' ? Plugins.currently_loading : ''); this.format_page = options.format_page; this.onFormatPage = options.onFormatPage; this.onStart = options.onStart; Vue.set(ModelLoader.loaders, id, this); if (this.format_page && this.format_page.component) { Vue.component(`format_page_${this.id}`, this.format_page.component) } Blockbench.dispatchEvent('construct_model_loader', {loader: this}); } new() { this.onStart(); } delete() { Vue.delete(ModelLoader.loaders, this.id); Blockbench.dispatchEvent('delete_model_loader', {loader: this}); } } ModelLoader.loaders = {}; (function() { /*$.getJSON('./content/news.json').then(data => { addStartScreenSection('new_version', data.new_version) })*/ var news_call = $.ajax({ cache: false, url: 'https://web.blockbench.net/content/news.json', dataType: 'json' }); documentReady.then(() => { //Twitter let twitter_ad; if (Blockbench.startup_count < 20 && Blockbench.startup_count % 5 === 4) { twitter_ad = true; addStartScreenSection({ color: '#1da1f2', text_color: '#ffffff', graphic: {type: 'icon', icon: 'fab.fa-twitter'}, text: [ {type: 'h2', text: 'Blockbench on Twitter'}, {text: 'Follow Blockbench on Twitter for the latest news as well as cool models from the community! [twitter.com/blockbench](https://twitter.com/blockbench/)'} ], last: true }) } //Discord if (Blockbench.startup_count < 6 && !twitter_ad) { addStartScreenSection({ color: '#5865F2', text_color: '#ffffff', graphic: {type: 'icon', icon: 'fab.fa-discord'}, text: [ {type: 'h2', text: 'Discord Server'}, {text: 'You need help with modeling or you want to chat about Blockbench? Join the official [Blockbench Discord](https://discord.gg/WVHg5kH)!'} ], last: true }) } // Quick Setup if (Blockbench.startup_count <= 1) { let section = Interface.createElement('section', {id: 'quick_setup'}); document.querySelector('#start_screen #splash_screen').after(section); new Vue({ data() {return { language: Language.code, language_original: Language.code, languages: Language.options, keymap: 'default', keymap_changed: false, theme: 'dark', keymap_options: { default: tl('action.load_keymap.default'), mouse: tl('action.load_keymap.mouse'), blender: 'Blender', cinema4d: 'Cinema 4D', maya: 'Maya', }, }}, methods: { tl, close() { this.$el.remove(); }, reload() { Blockbench.reload(); }, loadTheme(theme_id) { this.theme = theme_id; let theme = CustomTheme.themes.find(t => t.id == theme_id); if (theme) CustomTheme.loadTheme(theme); }, getThemeThumbnailStyle(theme_id) { let theme = CustomTheme.themes.find(t => t.id == theme_id); let style = {}; if (!theme) return style; for (let key in theme.colors) { style[`--color-${key}`] = theme.colors[key]; } return style; }, openThemes() { BarItems.theme_window.click(); } }, watch: { language(v) { settings.language.set(v); Settings.save(); }, keymap(keymap, old_keymap) { this.keymap_changed = true; let success = Keybinds.loadKeymap(keymap, true); if (!success) this.keymap = old_keymap; } }, template: `
    clear

    ${tl('mode.start.quick_setup')}

    {{ tl('action.load_keymap.' + keymap + '.desc') }}

    refresh

    {{ tl('message.restart_to_update') }}

    Dark
    Light
    Contrast
    more_horiz
    {{ tl('mode.start.quick_setup.more_themes') }}
    ` }).$mount(section); } }) Promise.all([news_call, documentReady]).then((data) => { if (!data || !data[0]) return; data = data[0]; //Update Screen if (Blockbench.hasFlag('after_update') && data.new_version) { data.new_version.insert_after = 'splash_screen' addStartScreenSection('new_version', data.new_version); jQuery.ajax({ url: 'https://blckbn.ch/api/event/successful_update', type: 'POST', data: { version: Blockbench.version } }) } if (data.psa) { (function() { if (typeof data.psa.version == 'string') { if (data.psa.version.includes('-')) { limits = data.psa.version.split('-'); if (limits[0] && compareVersions(limits[0], Blockbench.version)) return; if (limits[1] && compareVersions(Blockbench.version, limits[1])) return; } else { if (data.psa.version != Blockbench.version) return; } } addStartScreenSection(data.psa) })() } }) })()