This commit is contained in:
Korbs 2024-01-17 21:37:03 -05:00
parent 8da8f7fc9e
commit cdc1e2aa5f
No known key found for this signature in database
12 changed files with 230 additions and 12 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ Penpot-Desktop.dmg
yarn.lock yarn.lock
package-lock.json package-lock.json
pnpm-lock.yaml pnpm-lock.yaml
.yarn

Binary file not shown.

View file

@ -1,5 +1,5 @@
<sl-alert id="noinstance" variant="warning"> <sl-alert id="noinstance" variant="warning">
<sl-icon slot="icon" name="exclamation-triangle"></sl-icon> <sl-icon slot="icon" name="exclamation-triangle"></sl-icon>
<strong>No Instance Detected</strong><br /> <strong>No Instance Detected</strong><br />
Your instance setting is not set, please set one. <a href="#" onclick="localStorage.setItem('Instance', 'https://design.penpot.app/'); location.href = 'index.html'">Reset Setting</a> Your instance setting is not set, please set one. <a href="#" onclick="localStorage.setItem('Instance', 'https://design.penpot.app/'); window.api.send('ReloadApp')">Reset Setting</a>
</sl-alert> </sl-alert>

View file

@ -4,7 +4,7 @@
<h2>Instance</h2> <h2>Instance</h2>
</div> </div>
<div class="settings-section-content"> <div class="settings-section-content">
<input id="InstanceField" type="url" pattern="https?://.*" placeholder="https://design.penpot.app/" value=""/> <input style="width: -webkit-fill-available;" id="InstanceField" type="url" pattern="https?://.*" placeholder="https://design.penpot.app/" value=""/>
<input id="InstanceSaveButton" type="button" value="Save" onclick="InstanceSave()" /> <input id="InstanceSaveButton" type="button" value="Save" onclick="InstanceSave()" />
</div> </div>
<sl-details style="max-width: 320px;" summary="What is an instance?">A server running Penpot, is called an instance. Their can be many and you don't really need to choose one, commonly you only need to choose the offiical one that is ran by Penpot or to self-host your own.</sl-details> <sl-details style="max-width: 320px;" summary="What is an instance?">A server running Penpot, is called an instance. Their can be many and you don't really need to choose one, commonly you only need to choose the offiical one that is ran by Penpot or to self-host your own.</sl-details>

View file

@ -2,11 +2,11 @@
<style> <style>
:host { :host {
--tabgroup-background: transparent !important; --tabgroup-background: transparent !important;
--tab-background: #1f1f1f !important; --tab-background: transparent !important;
--tab-color: #ffffff !important; --tab-color: #ffffff !important;
--tab-border-color: transparent !important; --tab-border-color: transparent !important;
--tab-active-background: #303236 !important; --tab-active-background: #34393c !important;
--tag-hover-background: #3d3d3d !important; --tag-hover-background: #34393c !important;
--button-font-size: 15px !important; --button-font-size: 15px !important;
--button-background: none !important; --button-background: none !important;
--button-color: #696a6c !important; --button-color: #696a6c !important;

View file

@ -5,7 +5,7 @@
</sl-tooltip> </sl-tooltip>
<!-- Titlebar Buttons --> <!-- Titlebar Buttons -->
<button><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000" style="--darkreader-inline-color: #e8e6e3;" data-darkreader-inline-color=""><path d="M6 12H18" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="--darkreader-inline-stroke: #000000;" data-darkreader-inline-stroke=""></path></svg></button> <button class="linux-titlebar" onclick="window.api.send('MinimizeWindow')"><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000" style="--darkreader-inline-color: #e8e6e3;" data-darkreader-inline-color=""><path d="M6 12H18" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="--darkreader-inline-stroke: #000000;" data-darkreader-inline-stroke=""></path></svg></button>
<button><?xml version="1.0" encoding="UTF-8"?><svg style="width: 12px;" width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M21 3.6V20.4C21 20.7314 20.7314 21 20.4 21H3.6C3.26863 21 3 20.7314 3 20.4V3.6C3 3.26863 3.26863 3 3.6 3H20.4C20.7314 3 21 3.26863 21 3.6Z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></button> <button class="linux-titlebar" onclick="window.api.send('MaximizeWindow')"><?xml version="1.0" encoding="UTF-8"?><svg style="width: 12px;" width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M21 3.6V20.4C21 20.7314 20.7314 21 20.4 21H3.6C3.26863 21 3 20.7314 3 20.4V3.6C3 3.26863 3.26863 3 3.6 3H20.4C20.7314 3 21 3.26863 21 3.6Z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>
<button><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000" style="--darkreader-inline-color: #e8e6e3;" data-darkreader-inline-color=""><path d="M6.75827 17.2426L12.0009 12M17.2435 6.75736L12.0009 12M12.0009 12L6.75827 6.75736M12.0009 12L17.2435 17.2426" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="--darkreader-inline-stroke: #000000;" data-darkreader-inline-stroke=""></path></svg></button> <button class="linux-titlebar" onclick="window.close()"><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000" style="--darkreader-inline-color: #e8e6e3;" data-darkreader-inline-color=""><path d="M6.75827 17.2426L12.0009 12M17.2435 6.75736L12.0009 12M12.0009 12L6.75827 6.75736M12.0009 12L17.2435 17.2426" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="--darkreader-inline-stroke: #000000;" data-darkreader-inline-stroke=""></path></svg></button>
</div> </div>

View file

@ -1 +1 @@
body{background:#1d1f20}.titlebar{position:fixed;top:0px;right:0px;width:max-content;text-align:right;margin:4px 4px 0px 0px;cursor:default;z-index:5;app-region:no-drag}.titlebar button{width:32px;height:32px;font-size:0px;border:none;border-radius:6px;background:rgba(0,0,0,0)}.titlebar button:hover{background:#303236}.titlebar button svg{width:16px;height:16px;filter:invert(1)}sl-include.alert-modal{position:fixed;z-index:50;bottom:24px;left:50%;transform:translate(-50%);width:max-content}drag{position:fixed;top:0px;left:0px;width:100%;height:50px;app-region:drag;z-index:1}.dropdown-modal{position:fixed;top:40px;right:0px;z-index:50;display:none;flex-direction:column;background:#242428;border-radius:6px;border:1px #36363b solid;margin:6px;min-width:250px;transition:1s all}.dropdown-modal div:nth-child(1)>div.settings-section-header{border-radius:4px 4px 0px 0px}.dropdown-modal .settings-section-header{background:#303236;padding:6px 0px 6px 16px;font-size:12px}.dropdown-modal .settings-section-header h2{margin:0px}.dropdown-modal .settings-section-content{display:flex;margin:12px}.dropdown-modal .settings-section-content input{padding:6px 12px;border-radius:4px;border:1px #656565 solid;margin-right:6px}.dropdown-modal .settings-section-content input#InstanceSaveButton{background:#575151;color:#fff;border:none;border-radius:4px;padding:0px 12px} body{background:#1d1f20;font-family:arial}.titlebar{position:fixed;top:0px;right:0px;width:max-content;text-align:right;margin:4px 4px 0px 0px;cursor:default;z-index:5;app-region:no-drag}.titlebar .linux-titlebar{display:none}.titlebar button{width:32px;height:32px;font-size:0px;border:none;border-radius:6px;background:rgba(0,0,0,0)}.titlebar button:hover{background:#303236}.titlebar button svg{width:16px;height:16px;filter:invert(1)}sl-include.alert-modal{position:fixed;z-index:50;bottom:24px;left:50%;transform:translate(-50%);width:max-content}drag{position:fixed;top:0px;left:0px;width:100%;height:50px;app-region:drag;z-index:1}.dropdown-modal{position:fixed;top:40px;right:0px;z-index:50;display:none;flex-direction:column;background:#242428;border-radius:6px;border:1px #36363b solid;margin:6px;min-width:250px;width:300px;transition:1s all}.dropdown-modal div:nth-child(1)>div.settings-section-header{border-radius:4px 4px 0px 0px}.dropdown-modal .settings-section-header{background:#303236;padding:6px 0px 6px 16px;font-size:12px}.dropdown-modal .settings-section-header h2{margin:0px}.dropdown-modal .settings-section-content{display:flex;margin:12px}.dropdown-modal .settings-section-content input{padding:6px 12px;border-radius:4px;border:1px #656565 solid;margin-right:6px}.dropdown-modal .settings-section-content input#InstanceSaveButton{background:#575151;color:#fff;border:none;border-radius:4px;padding:0px 12px}

View file

@ -1,5 +1,6 @@
body { body {
background: #1d1f20; background: #1d1f20;
font-family: arial;
} }
.titlebar { .titlebar {
@ -12,6 +13,9 @@ body {
cursor: default; cursor: default;
z-index: 5; z-index: 5;
app-region: no-drag; app-region: no-drag;
.linux-titlebar {
display: none;
}
button { button {
width: 32px; width: 32px;
height: 32px; height: 32px;
@ -61,6 +65,7 @@ drag {
border: 1px hsl(240 4.6% 22%) solid; border: 1px hsl(240 4.6% 22%) solid;
margin: 6px; margin: 6px;
min-width: 250px; min-width: 250px;
width: 300px;
transition: 1s all; transition: 1s all;
div:nth-child(1) > div.settings-section-header { div:nth-child(1) > div.settings-section-header {
border-radius: 4px 4px 0px 0px; border-radius: 4px 4px 0px 0px;

169
src/process/menu.js Normal file
View file

@ -0,0 +1,169 @@
const {app, Menu} = require('electron')
let Platform = require('./platform')
module.exports = {
MainMenu: function () {
const template = [
...(process.platform === 'darwin' ? [{
label: app.name,
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
}] : []),
{
label: 'File',
submenu: [
{
label: "New Tab",
accelerator: "CmdOrCtrl+T",
click: () => {
mainWindow.webContents.executeJavaScript(`document.querySelector("tab-group").shadowRoot.querySelector("div > nav > div.buttons > button").click()`)
}
},
{
label: "Close Tab",
accelerator: "CmdOrCtrl+W",
click: () => {
mainWindow.webContents.executeJavaScript(`document.querySelector("tab-group").shadowRoot.querySelector("div > nav > div.tabs > div.tab.visible.active > span.tab-close > button").click()`)
}
}
]
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
...(process.platform === 'darwin' ? [
{ role: 'pasteAndMatchStyle' },
{ role: 'delete' },
{ role: 'selectAll' },
{ type: 'separator' },
{
label: 'Speech',
submenu: [
{ role: 'startSpeaking' },
{ role: 'stopSpeaking' }
]
}
] : [
{ role: 'delete' },
{ type: 'separator' },
{ role: 'selectAll' }
])
]
},
{
label: 'View',
submenu: [
{
label: 'Reload Tab',
accelerator: 'CmdOrCtrl+R',
click: async () => {
mainWindow.webContents.executeJavaScript(`document.querySelector("tab-group").shadowRoot.querySelector("webview.visible").reload()`)
setTimeout(() => {Platform.CSS()}, 1000)
}
},
{
label: 'Reload Window',
accelerator: 'CmdOrCtrl+Shift+R',
click: async () => {
mainWindow.reload()
setTimeout(() => {Platform.CSS()}, 1000)
}
},
{ role: 'toggleDevTools' },
{
label: 'Open Tab Developer Tools',
accelerator: 'CmdOrCtrl+Shift+D',
click: () => {
mainWindow.webContents.executeJavaScript(`document.querySelector("body > tab-group").shadowRoot.querySelector("div > div > webview.visible").openDevTools()`)
}},
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
...(process.platform === 'darwin' ? [
{ type: 'separator' },
{ role: 'front' },
{ type: 'separator' },
{
role: 'close',
accelerator: "CmdOrCtrl+Shift+W"
}
] : [
{
role: 'close',
accelerator: "CmdOrCtrl+Shift+W"
}
])
]
},
{
role: 'help',
submenu: [
{
label: 'User Guide',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://help.penpot.app/user-guide/')
}
},
{
label: 'FAQ',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://help.penpot.app/faqs')
}
},
{
label: 'Learn to Self-host',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://penpot.app/self-host')
}
},
{
label: 'Penpot Community',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://community.penpot.app/')
}
},
{ type: 'separator'},
{
label: 'Source Code',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://sudovanilla.com/code/Korbs/Penpot-Desktop/-/tree/main')
}
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
}
}

12
src/process/platform.js Normal file
View file

@ -0,0 +1,12 @@
const {app} = require('electron')
module.exports = {
CSS: function () {
if (process.platform === 'darwin') {
setTimeout(() => {
mainWindow.webContents.executeJavaScript(`document.querySelector("body").style.backgroundColor = 'transparent'`)
mainWindow.webContents.executeJavaScript(`document.querySelector("tab-group").shadowRoot.querySelector("nav").style.left = '80px'`)
}, 1500);
}
}
}

14
src/process/preload.js Normal file
View file

@ -0,0 +1,14 @@
const { contextBridge, ipcRenderer} = require("electron")
const path = require('path')
contextBridge.exposeInMainWorld( "api", { send: (channel, data) => {let validChannels = [
"updateApp",
"ReloadApp",
"MaximizeWindow",
"UnmaximizeWindow",
"MinimizeWindow"
]
if (validChannels.includes(channel)) {ipcRenderer.send(channel, data)}}})
delete process.env.ELECTRON_ENABLE_SECURITY_WARNINGS
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true

View file

@ -2,6 +2,9 @@ const {app, BrowserWindow, ipcMain, ipcRenderer} = require('electron')
const windowStateKeeper = require('electron-window-state') const windowStateKeeper = require('electron-window-state')
const path = require('path') const path = require('path')
const Menu = require('./menu')
const Platform = require('./platform')
module.exports = { module.exports = {
create: function () { create: function () {
let mainWindowState = windowStateKeeper({defaultWidth: 1400,defaultHeight: 900}) let mainWindowState = windowStateKeeper({defaultWidth: 1400,defaultHeight: 900})
@ -16,10 +19,10 @@ module.exports = {
// Theme // Theme
darkTheme: true, darkTheme: true,
transparent: global.transparent, transparent: global.transparent,
vibrancy: "sidebar", vibrancy: "header",
// Titlebar // Titlebar
titleBarStyle: 'hidden', titleBarStyle: 'hidden',
trafficLightPosition: { x: 10, y: 12 }, // for macOS trafficLightPosition: { x: 16, y: 12 }, // for macOS
titleBarOverlay: { // For Windows titleBarOverlay: { // For Windows
color: '#1f1f1f', color: '#1f1f1f',
symbolColor: 'white', symbolColor: 'white',
@ -30,14 +33,28 @@ module.exports = {
frame: false, frame: false,
icon: global.AppIcon, icon: global.AppIcon,
webPreferences: { webPreferences: {
// preload: path.join(app.getAppPath(), '/src/process/preload.js'), preload: path.join(app.getAppPath(), 'src/process/preload.js'),
sandbox: false, // App doens't load properly if enabled sandbox: false, // App doens't load properly if enabled
webviewTag: true webviewTag: true
} }
}) })
mainWindow.loadFile('src/base/index.html') mainWindow.loadFile('src/base/index.html')
// IPC Functions
ipcMain.on('ReloadApp', () => {mainWindow.reload(); Platform.CSS()})
ipcMain.on('MaximizeWindow', () => {mainWindow.maximize()})
ipcMain.on('UnmaximizeWindow', () => {mainWindow.restore()})
ipcMain.on('MinimizeWindow', () => {mainWindow.minimize()})
// Move Tabs when entering or existing fullscreen on macOS
if (process.platform === 'darwin') {
mainWindow.on('enter-full-screen', (e, cmd) => {mainWindow.webContents.executeJavaScript(`document.querySelector("tab-group").shadowRoot.querySelector("nav").style.left = '0px'`)})
mainWindow.on('leave-full-screen', (e, cmd) => {mainWindow.webContents.executeJavaScript(`document.querySelector("tab-group").shadowRoot.querySelector("nav").style.left = '80px'`)})
}
// Other Functions // Other Functions
mainWindowState.manage(mainWindow) mainWindowState.manage(mainWindow)
Menu.MainMenu()
Platform.CSS()
} }
} }