iT邦幫忙

2021 iThome 鐵人賽

DAY 27
2
Modern Web

JavaScript Easy Go!系列 第 27

#27 做點 GUI 吧!

今天就來做些 GUI 吧!

用 HTML + CSS 先把結構弄出來

app.html

<html>
    <head>
        <meta charset="UTF-8" />
        <link href="./style.css" rel="stylesheet" />
        <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
        <title>Click! Serve!</title>
    </head>
    <body>
        <div id="container">
            <div id="controls">
                <div id="launch-area">
                    <button>啟動</button>
                </div>
                <div id="config-area">
                    <label>資料夾</label>
                    <div>
                        <input type="text" id="folder" value="" />
                        <button id="folder-select">選擇</button>
                    </div>
                    <label>Port</label>
                    <div>
                        <input type="number" id="port" value="" />
                    </div>
                    <label>Log</label>
                    <div>
                        <div class="toggle">
                            <input id="log" type="checkbox" /><br />
                            <b class="b switch"></b>
                            <b class="b track"></b>
                        </div>
                    </div>
                    <label>Log File</label>
                    <div>
                        <input type="text" id="logfile" value="" />
                        <button id="logfile-select">選擇</button>
                    </div>
                </div>
            </div>
            <div id="logs"></div>
        </div>
        <script src="./app.js"></script>
    </body>
</html>

style.css

:root {
    /* 使用 Nord Theme 的配色,沒有為什麼,只是我喜歡而已 */
    --nord0: #2e3440;
    --nord1: #3b4252;
    --nord2: #434c5e;
    --nord3: #4c566a;
    --nord4: #d8dee9;
    --nord5: #e5e9f0;
    --nord6: #eceff4;
    --nord7: #8fbcbb;
    --nord8: #88c0d0;
    --nord9: #81a1c1;
    --nord10: #5e81ac;
    --nord11: #bf616a;
    --nord12: #d08770;
    --nord13: #ebcb8b;
    --nord14: #a3be8c;
    --nord15: #b48ead;
}

/* body 預設會有個 padding,先把它弄掉 */
html,
body {
    margin: 0;
    padding: 0;
    overflow: hidden;
}

body {
    background: var(--nord6);
    color: var(--nord0);
}

#container {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

/* 上面的那個區塊 */
#controls {
    width: 100%;
    height: 320px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    border-bottom: var(--nord4) solid 1px;
}

#launch-area {
    width: 320px;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}

#launch-area > button {
    width: 160px;
    height: 160px;
    border-radius: 50%;
    background: var(--nord8);
    color: var(--nord1);
    font-size: 2.2rem;
    border: none;
    cursor: pointer;
    transition: all 0.3s;
}

#launch-area > button:hover {
    width: 180px;
    height: 180px;
    border-radius: 50%;
    background: var(--nord9);
    color: var(--nord6);
}

#config-area {
    flex: 1;
    height: 100%;
    display: grid;
    align-content: space-evenly;
    justify-items: center;
    grid-template-columns: 100px 1fr;
    grid-gap: 10px;
    font-size: 1.4rem;
}

#config-area > label {
    text-align: right;
    display: inline-block;
    width: 100%;
}

#config-area > div {
    width: calc(100% - 10px);
    padding: 0 10px 0 0;
    display: flex;
    align-items: center;
}

#config-area input,
#config-area button {
    font-size: 1.4rem;
    background: var(--nord5);
    border: none;
    border-radius: 6px;
    padding: 4px 8px;
    transition: all 0.3s;
}

#config-area input:hover,
#config-area input:focus,
#config-area button:hover,
#config-area button:focus {
    outline: none;
    background: var(--nord4);
}

#folder,
#logfile {
    flex: 1;
}

#config-area #folder-select,
#config-area #logfile-select {
    height: 100%;
    width: 100px;
    padding: 0;
    margin: 0 8px;
    cursor: pointer;
}

#port {
    width: 120px;
}

/* 下面的那個區塊 */
#logs {
    width: 100%;
    flex: 1;
    overflow: auto;
    background: var(--nord5);
}

/* .toggle 就是那個 iOS 風格按鈕 */
.toggle {
    position: absolute;
    width: 45px;
    height: 30px;
    border-radius: 75px;
    background-color: var(--nord5);
    overflow: hidden;
    box-shadow: inset 0 0 1.5px 0.75px var(--nord4);
    margin: 8px 0;
}

.toggle > input[type="checkbox"] {
    position: absolute;
    display: block;
    cursor: pointer;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    z-index: 6;
}

.toggle > input[type="checkbox"] ~ .switch {
    position: absolute;
    left: 1.5px;
    top: 1.5px;
    bottom: 1.5px;
    right: 16.5px;
    background-color: var(--nord6);
    border-radius: 27px;
    z-index: 1;
    transition: 0.25s cubic-bezier(0.785, 0.135, 0.15, 0.86);
    transition-property: left, right;
    transition-delay: 0s, 0.03s;
    box-shadow: 0 0.75px 1.5px var(--nord4);
}

.toggle > input[type="checkbox"] ~ .track {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    transition: 0.25s cubic-bezier(0.785, 0.135, 0.15, 0.86);
    box-shadow: inset 0 0 0 1.5px var(--nord4);
    border-radius: 30px;
}

.toggle > input[type="checkbox"]:checked ~ .track {
    box-shadow: inset 0 0 0 15px var(--nord8);
}

.toggle > input[type="checkbox"]:checked ~ .switch {
    right: 1.5px;
    left: 16.5px;
    transition: 0.25s cubic-bezier(0.785, 0.135, 0.15, 0.86);
    transition-property: left, right;
    transition-delay: 0.03s, 0s;
}

大概就是這樣,做點樣式,然後用 transition 做切換或滑過的動畫。

原生檔案位置選取

Electron 可以讓我們用原生檔案視窗選取檔案或資料夾。

main.js

// 把前面引用加上 ipc 及 dialog
const { app, BrowserWindow, dialog, ipcMain: ipc } = require("electron");

// agent.js 會送來請求,我們開原生的 Dialog 再把選取的結果傳回去
ipc.on("select-folder", async (evt) => {
    const path = await dialog.showOpenDialog({
        properties: ["openDirectory"],
        title: "請選擇資料夾位置",
        defaultPath: process.cwd(),
    });
    evt.sender.send("selected-folder", path);
});

ipc.on("select-logfile", async (evt) => {
    const path = await dialog.showOpenDialog({
        properties: ["openFile"],
        title: "請選擇 Log 檔位置",
        defaultPath: process.cwd() + "/log.txt",
    });
    evt.sender.send("selected-logfile", path);
});

agent.js

const { ipcRenderer: ipc } = require("electron");

// 收到 main.js 回傳的位置,套用到 input 上
ipc.on("selected-folder", (evt, path) => {
    if (path.canceled) return;
    document.querySelector("#folder").value = path.filePaths[0];
});
ipc.on("selected-logfile", (evt, path) => {
    if (path.canceled) return;
    document.querySelector("#logfile").value = path.filePaths[0];
});

// 當 DOM 載入完成後填上初始值
document.addEventListener("DOMContentLoaded", () => {
    document.querySelector("#folder").value = process.cwd() + "/www";
    document.querySelector("#port").value = "80";
    document.querySelector("#log").checked = false;
    document.querySelector("#logfile").value = process.cwd() + "/log.txt";

    registerListener();
});

function registerListener() {
    // 選擇資料夾,用 ipc 與 main.js 溝通
    document.querySelector("#folder-select").addEventListener("click", () => {
        ipc.send("select-folder");
    });
    document.querySelector("#logfile-select").addEventListener("click", () => {
        ipc.send("select-logfile");
    });
}

每日鐵人賽熱門 Top 10 (1010)

以 10/10 20:00 ~ 10/11 20:00 文章觀看數增加值排名

  1. +116 [職場]拒絕做白工!讓自己的努力效益最大化
    • 作者: 寶寶出頭天
    • 系列:全端工程師生存筆記
  2. +112 [DAY-27] 適合你的 才是真正的好職涯
    • 作者: flipsyde
    • 系列:帶腦去上班 & No Rules Rules
  3. +110 Day 26: 人工智慧在音樂領域的應用 (AI作曲 - 生成對抗網路 Gan (幹) )
    • 作者: fd2
    • 系列:人工智慧在音樂領域的應用
  4. +109 【Day25-評估】連韓組長也混淆的混淆矩陣?——學會正確解讀模型價值的常用指標:Recall, Precision, Specificity, F1-Score
    • 作者: owo
    • 系列:資料三十-那些最基本的資料處理與分析技能
  5. +105 D26 - 「來互相傷害啊!」:站在巨人的肩膀上
    • 作者: 鱈魚
    • 系列:你渴望連結嗎?將 Web 與硬體連上線吧!
  6. +103 Proxmox VE 啟用客體機複寫及搭配遷移功能使用
    • 作者: Jason Cheng (節省哥)
    • 系列:突破困境:企業開源虛擬化管理平台
  7. +98 LeetCode 雙刀流:62. Unique Paths
    • 作者: WeiYuan
    • 系列:LeetCode 雙刀流:Python x JavaScript
  8. +91 [Python 爬蟲這樣學,一定是大拇指拉!] DAY26 - 實戰演練:多執行緒 - 抓取多個個股收盤價
    • 作者: GreedIsGood
    • 系列:Python 爬蟲這樣學,一定是大拇指拉!
  9. +89 Day 26 批次網路影片下載工具 - youtube-dl-server
    • 作者: smlpoints
    • 系列:以 Docker 為始的多種開源服務初探
  10. +89 [Day26] Vue3 E2E Testing: Cypress 實戰之 Todo MVC (中)
    • 作者: Mia Yang
    • 系列:前端工程師在工作中的各種實戰技能 (Vue 3)

上一篇
#26 初探 Electron
下一篇
#28 Click! Serve! Desktop
系列文
JavaScript Easy Go!31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言