P.S. Каждая часть — это часть, сама по себе смысла не имеет, чтобы обзавестись необходимым контекстом и не испытывать когнитивный диссонанс от отсутствия так необходимых блоков текста начните читать с 1 части

CallbackElectron компонент, элемент обратной связи.

Структура папок:

callback
¦
¦   index.js
¦
L---client // Все что относится к клиенту
    ¦   image.jpg
    ¦   index.html
    ¦   style.css
    ¦
    L---fonts
            font1.woff2
            font2.woff2
            font3.woff2
            font4.woff2
            font5.woff2
            font6.woff2
            font7.woff2


index.js — Файл, в котором создается Electron компонент.

Cодержимое файла index.js.

Код
const { BrowserWindow, ipcMain } = require('electron')

module.exports = class Callback {
    constructor(parent) {
        // Создаем окно
        this.root = new BrowserWindow({
            frame: false, // Убираем рамку 
            transparent: true, // Убираем рамку 
            resizable: false, // Запрещаем масштабирование
            show: false, // Запрещаем показывать окно после загрузки
            width: 175,
            height: 463,
            center: true,
            parent
        })
        
        // Загружаем страницу
        this.root.loadURL(`${__dirname}/client/index.html`)

        // Устанавливаем обработчик сигнала от окна (закрытие окна)
        ipcMain.on('CALLBACK_CLOSE', e => {
            this.root.hide()
            e.returnValue = 'ok'
        })
    }

    ready() {
        // Ожидаем пока окно полностью инициализируется
        return new Promise(res => {
            this.root.once('ready-to-show', res)
        })
    }

    show() {
        // Показываем окно
        this.root.show()
    }

    hide() {
        // Скрываем окно
        this.root.hide()
    }
}


index.html — HTML-страница окна.

Cодержимое файла index.html:

Код
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <link rel='stylesheet' type='text/css' href='style.css?ss'>
</head>
<body>
<div class='body'>
    <div class='avatar'></div>
    <div class='info'>
        <div class='name'><b>JSus</b> Dev</div>
        <div class='background'><i>"JavaScript программист и разработчик электронных устройств"</i></div>
        <a onclick='open_link("https://github.com/JsusDev/JS.VPN-Client");event.preventDefault()' href='#' class='gh'>GitHub</a>
        <a onclick='open_link("https://...");event.preventDefault()' href='#' target='_blank'>Telegram me</a>
        <a onclick='open_link("https://...");event.preventDefault()' href='#' target='_blank'>Telegram channel</a>
        <div class='btn'>Закрыть</div>
    </div>
</div>
<script>
const btn = document.getElementsByClassName('btn')[0]
   , { ipcRenderer, shell } = require('electron')

// Открывает ссылки в вашем браузере по умолчанию
const open_link = (url) => shell.openExternal(url)

// Отправляет сигнал CALLBACK_CLOSE (Скрытие окна)
btn.addEventListener('click', () => {
    ipcRenderer.sendSync('CALLBACK_CLOSE')
})
</script>
</body>
</html>


style.css — HTML-страница окна.

Cодержимое файла style.css:

Код
@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font1.woff2) format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}


/* cyrillic */

@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font2.woff2) format('woff2');
    unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}


/* greek-ext */

@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font3.woff2) format('woff2');
    unicode-range: U+1F00-1FFF;
}


/* greek */

@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font4.woff2) format('woff2');
    unicode-range: U+0370-03FF;
}


/* vietnamese */

@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font5.woff2) format('woff2');
    unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}


/* latin-ext */

@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font6.woff2) format('woff2');
    unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* latin */

@font-face {
    font-family: 'Source Sans Pro';
    font-style: normal;
    font-weight: 400;
    src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font7.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

* {
    font-family: 'Source Sans Pro', sans-serif;
    padding: 0;
    margin: 0;
    overflow: hidden;
    background: rgba(0, 0, 0, 0);
}

.body {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
}

.avatar {
    width: 120px;
    height: 120px;
    border-radius: 100%;
    border: 13px solid #242424;
    background: url('image.jpg');
    background-size: cover;
}

.info {
    margin-top: 10px;
    font-size: 14px;
    background: rgba(36, 39, 39, 0.9);
    color: #eee;
    width: 135px;
    border-radius: 10px;
    padding: 10px 20px 10px 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.name {
    font-size: 23px;
    margin-bottom: 10px;
}

.background {
    text-align: center;
    margin: 10px;
}

a {
    user-select: none;
    cursor: pointer;
    width: 100%;
    display: block;
    color: #bbb;
    text-decoration: none;
    font-size: 13px;
}

a:hover {
    color: #ccc;
}

.gh {
    margin: 4px;
    text-align: center;
    margin-bottom: 10px;
}

.btn {
    cursor: pointer;
    margin-top: 2px;
    padding: 4px 10px 4px 10px;
    border-radius: 6px;
    user-select: none;
    margin: 10px 10px 0px 10px;
}

.btn:hover {
    color: #ccc
}


Application

Использование в приложении: /app/Callback

API

Интерфейс компонента Callback:

const { app }   = require('electron')
    , CALLBACK  = require('./../../app/components/callback')

app.on('ready', async() => {

    const Callback = new CALLBACK()

    await Callback.ready()

    // Показываем окно
    Callback.show()
})

Test

Версия для тестирования: /app_test/Callback

image

10 часть — Объединение всех компонентов


Собственный VPN клиент на JavaScript by JSus

Комментарии (0)