implement nhentai login
This commit is contained in:
parent
31e0b6d448
commit
35b778bd0b
|
@ -7,4 +7,4 @@ printWidth: 80
|
|||
overrides:
|
||||
- files: '*.svelte'
|
||||
options:
|
||||
parser: vue
|
||||
parser: html
|
||||
|
|
|
@ -6318,6 +6318,24 @@
|
|||
"tough-cookie": "~2.4.3",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"dev": true
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"psl": "^1.1.24",
|
||||
"punycode": "^1.4.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
|
@ -6338,6 +6356,18 @@
|
|||
"request-promise-core": "1.1.2",
|
||||
"stealthy-require": "^1.1.1",
|
||||
"tough-cookie": "^2.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tough-cookie": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
|
@ -7424,21 +7454,14 @@
|
|||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
|
||||
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"psl": "^1.1.24",
|
||||
"punycode": "^1.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"dev": true
|
||||
}
|
||||
"ip-regex": "^2.1.0",
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/jsdom": "^12.2.3",
|
||||
"@types/node-fetch": "^2.3.7",
|
||||
"@types/tough-cookie": "^2.3.5",
|
||||
"@types/webpack": "^4.4.32",
|
||||
"electron": "^5.0.5",
|
||||
"electron-rebuild": "^1.8.5",
|
||||
|
@ -32,10 +35,13 @@
|
|||
"gulp-cli": "^2.2.0",
|
||||
"gulp-sourcemaps": "^2.6.5",
|
||||
"gulp-typescript": "^5.0.1",
|
||||
"jsdom": "^15.1.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"prettier": "^1.18.2",
|
||||
"sqlite3": "^4.0.9",
|
||||
"svelte": "^3.5.1",
|
||||
"svelte-loader": "^2.13.4",
|
||||
"tough-cookie": "^3.0.1",
|
||||
"ts-loader": "^6.0.3",
|
||||
"tslint": "^5.17.0",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import WebContents = Electron.WebContents;
|
||||
|
||||
declare type IpcEvent = {
|
||||
frameId: number;
|
||||
preventDefault: () => void;
|
||||
reply: (channel: string, ...args: any) => void;
|
||||
sender: WebContents;
|
||||
};
|
|
@ -6,7 +6,7 @@ import session from './main/services/session';
|
|||
|
||||
let mainWindow: Electron.BrowserWindow;
|
||||
|
||||
async function createWindow() {
|
||||
async function createWindow(): Promise<void> {
|
||||
session.init();
|
||||
|
||||
// Create the browser window.
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
import { ipcMain } from 'electron';
|
||||
import WebContents = Electron.WebContents;
|
||||
import nhentai from './../services/nhentai-crawler';
|
||||
|
||||
ipcMain.on(
|
||||
IpcChannels.Credentials,
|
||||
(
|
||||
event: {
|
||||
frameId: number;
|
||||
preventDefault: () => void;
|
||||
reply: (channel: string, ...args: any) => void;
|
||||
sender: WebContents;
|
||||
},
|
||||
...args: any
|
||||
) => {
|
||||
event.reply(IpcChannels.Pong, args);
|
||||
}
|
||||
);
|
||||
ipcMain.on(IpcChannels.Credentials, (event: IpcEvent, args: ICredentials) => {
|
||||
nhentai
|
||||
.login(args.name, args.password)
|
||||
.then(() => {
|
||||
console.log('success');
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('fail');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Tag } from './tag';
|
|||
|
||||
@Entity()
|
||||
export class Book extends MultiNamed {
|
||||
@OneToMany(() => Copy, copy => copy.original, {
|
||||
@OneToMany(() => Copy, (copy: Copy) => copy.original, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE',
|
||||
|
|
|
@ -11,7 +11,7 @@ const enum CopyTypes {
|
|||
|
||||
@Entity()
|
||||
export class CopyType extends Base {
|
||||
@ManyToOne(() => Copy, copy => copy.types, {
|
||||
@ManyToOne(() => Copy, (copy: Copy) => copy.types, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE',
|
||||
|
|
|
@ -15,7 +15,7 @@ import { Translator } from './translator';
|
|||
|
||||
@Entity()
|
||||
export class Copy extends Base {
|
||||
@ManyToOne(() => Book, book => book.copies, {
|
||||
@ManyToOne(() => Book, (book: Book) => book.copies, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE',
|
||||
|
@ -25,7 +25,7 @@ export class Copy extends Base {
|
|||
@Column({ nullable: false, default: false })
|
||||
public favorited: boolean;
|
||||
|
||||
@OneToMany(() => CopyType, copyType => copyType.copy, {
|
||||
@OneToMany(() => CopyType, (copyType: CopyType) => copyType.copy, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE',
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Source } from './source';
|
|||
|
||||
@Entity()
|
||||
export class Site extends MultiNamed {
|
||||
@OneToMany(() => Source, source => source.site, {
|
||||
@OneToMany(() => Source, (source: Source) => source.site, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE',
|
||||
|
|
|
@ -11,7 +11,7 @@ export class Source extends Base {
|
|||
})
|
||||
public uri: string;
|
||||
|
||||
@ManyToOne(() => Site, site => site.sources, {
|
||||
@ManyToOne(() => Site, (site: Site) => site.sources, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE',
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Connection, createConnection } from 'typeorm';
|
|||
|
||||
let connection: Connection;
|
||||
|
||||
function init() {
|
||||
function init(): void {
|
||||
initConnection();
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,10 @@ function initConnection(): void {
|
|||
// createConnection method will automatically read connection options
|
||||
// from your ormconfig file or environment variables
|
||||
createConnection('library')
|
||||
.then(c => {
|
||||
.then((c: Connection) => {
|
||||
connection = c;
|
||||
})
|
||||
.catch(reason => {
|
||||
.catch((reason: any) => {
|
||||
throw reason;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import { JSDOM } from 'jsdom';
|
||||
import { RequestInit, Response } from 'node-fetch';
|
||||
import RenaiError, { Errors } from '../../types/error';
|
||||
import fetch from './web-crawler';
|
||||
|
||||
const url = 'https://nhentai.net/';
|
||||
|
||||
const paths = {
|
||||
|
@ -6,39 +11,88 @@ const paths = {
|
|||
favorites: 'favorites/',
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
let loginPassword: string;
|
||||
// @ts-ignore
|
||||
let loginName: string;
|
||||
const usernameInput = 'username_or_email';
|
||||
const passwordInput = 'password';
|
||||
|
||||
function fetchNHentai(path: string): Promise<Document> {
|
||||
return fetch(`${url}${path}`, {
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res);
|
||||
interface ILoginMeta {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface ILoginAuth {
|
||||
[usernameInput]: string;
|
||||
[passwordInput]: string;
|
||||
}
|
||||
|
||||
interface ILoginParams extends ILoginMeta, ILoginAuth {}
|
||||
|
||||
function login(name: string, password: string): Promise<void> {
|
||||
return getLoginMeta()
|
||||
.then((meta: ILoginMeta) => {
|
||||
const loginParams: ILoginParams = {
|
||||
...meta,
|
||||
...{
|
||||
// tslint:disable-next-line: object-literal-sort-keys
|
||||
username_or_email: name,
|
||||
password,
|
||||
},
|
||||
};
|
||||
|
||||
return postNHentai(paths.login, {
|
||||
body: encodeURI(
|
||||
Object.keys(loginParams)
|
||||
.map((key: keyof ILoginParams) => `${key}=${loginParams[key]}`)
|
||||
.join('&')
|
||||
),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
})
|
||||
.then(() => {})
|
||||
.catch(() => Promise.reject(new RenaiError(Errors.ELOGINFAIL)));
|
||||
}
|
||||
|
||||
function getNHentai(path: string): Promise<Document> {
|
||||
return fetch(`${url}${path}`)
|
||||
.then((res: Response) => {
|
||||
return res.text();
|
||||
})
|
||||
.then(text => {
|
||||
const parser = new DOMParser();
|
||||
return parser.parseFromString(text, 'text/html');
|
||||
.then((text: string) => {
|
||||
const { document } = new JSDOM(text).window;
|
||||
return document;
|
||||
});
|
||||
}
|
||||
|
||||
function fetchLogin(): void {
|
||||
fetchNHentai(paths.login)
|
||||
.then(() => true)
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
function postNHentai(path: string, init: RequestInit = {}): Promise<Response> {
|
||||
return fetch(`${url}${path}`, { ...init, ...{ method: 'post' } });
|
||||
}
|
||||
|
||||
function setLoginCredentials(name: string, password: string): void {
|
||||
loginName = name;
|
||||
loginPassword = password;
|
||||
function getLoginMeta(): Promise<ILoginMeta> {
|
||||
return getNHentai(paths.login).then((document: Document) => {
|
||||
// tslint:disable-next-line: prefer-for-of
|
||||
for (let i = 0; i < document.forms.length; i++) {
|
||||
const form: HTMLFormElement = document.forms[i];
|
||||
const valueStore: ILoginMeta = {};
|
||||
let isLoginForm = false;
|
||||
// tslint:disable-next-line: prefer-for-of
|
||||
for (let j = 0; j < form.elements.length; j++) {
|
||||
const input = form.elements[j];
|
||||
const name = input.getAttribute('name');
|
||||
|
||||
if (name === usernameInput || name === passwordInput) {
|
||||
isLoginForm = true;
|
||||
} else if (name) {
|
||||
valueStore[name] = input.getAttribute('value');
|
||||
}
|
||||
}
|
||||
if (isLoginForm) {
|
||||
return valueStore;
|
||||
}
|
||||
}
|
||||
return Promise.reject(new RenaiError(Errors.ENOLOGIN));
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
setLoginCredentials,
|
||||
fetchLogin,
|
||||
login,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import nodeFetch, { RequestInit, Response } from 'node-fetch';
|
||||
import { Cookie, CookieJar } from 'tough-cookie';
|
||||
|
||||
const cookieJar: CookieJar = new CookieJar();
|
||||
|
||||
function fetch(url: string, init: RequestInit = {}): Promise<Response> {
|
||||
const headers: HeadersInit = {};
|
||||
cookieJar.getCookiesSync(url).forEach((cookie: Cookie) => {
|
||||
headers[cookie.key] = cookie.value;
|
||||
});
|
||||
const cookiedInit = {
|
||||
...init,
|
||||
...{ headers: { ...init.headers, ...headers } },
|
||||
};
|
||||
return nodeFetch(url, cookiedInit).then((res: Response) => {
|
||||
setCookies(res.headers.raw()['set-cookie'], url);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
function setCookies(header: string[], url: string): void {
|
||||
header.forEach((cookie: string) => {
|
||||
cookieJar.setCookieSync(cookie, url);
|
||||
});
|
||||
}
|
||||
|
||||
export default fetch;
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import App from './renderer/App.svelte';
|
||||
|
||||
(() =>
|
||||
((): void =>
|
||||
new App({
|
||||
target: document.querySelector('#app'),
|
||||
props: {
|
||||
|
|
|
@ -1,62 +1,74 @@
|
|||
<script>
|
||||
import Button from 'atoms/Button.svelte';
|
||||
import Divide from 'molecules/Divide.svelte';
|
||||
import api from 'services/api';
|
||||
import Bttn from 'atoms/Bttn.svelte';
|
||||
import Divide from 'molecules/Divide.svelte';
|
||||
import api from 'services/api';
|
||||
|
||||
let text = 'tach';
|
||||
let form = {
|
||||
name: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
function handleClick() {
|
||||
api.sendCredentials({ name: '1', password: '2' });
|
||||
}
|
||||
function handleClick() {
|
||||
api.sendCredentials(form);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--color-white: #fff;
|
||||
--color-black: #000;
|
||||
:root {
|
||||
--color-white: #fff;
|
||||
--color-black: #000;
|
||||
|
||||
--color-background: #242424;
|
||||
--color-foreground: #3a3a3a;
|
||||
--color-foreground-light: #696969;
|
||||
--color-accent: #454585;
|
||||
--color-accent-light: #6969ac;
|
||||
--color-background: #242424;
|
||||
--color-foreground: #3a3a3a;
|
||||
--color-foreground-light: #696969;
|
||||
--color-accent: #454585;
|
||||
--color-accent-light: #6969ac;
|
||||
|
||||
--color-text: var(--color-white);
|
||||
--color-text: var(--color-white);
|
||||
|
||||
font-family: sans-serif;
|
||||
}
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
:global(*) {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
:global(*) {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:global(html) {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
:global(html) {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
:global(body) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
:global(body) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<main>
|
||||
<Divide>
|
||||
<div slot="1">
|
||||
<h1>Hello World</h1>
|
||||
<p>{ text }</p>
|
||||
<Button on:click="{handleClick}">test-inhalt</Button>
|
||||
<h1>Login</h1>
|
||||
<form>
|
||||
<label>
|
||||
<span>Username/Email</span>
|
||||
<input bind:value="{form.name}" />
|
||||
</label>
|
||||
<label>
|
||||
<span>Password</span>
|
||||
<input bind:value="{form.password}" type="password" />
|
||||
</label>
|
||||
<Bttn on:click="{handleClick}">submit</Bttn>
|
||||
</form>
|
||||
</div>
|
||||
<div slot="2">
|
||||
<Divide mode="v">
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<style>
|
||||
.button {
|
||||
border: none;
|
||||
color: var(--color-text);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
outline-color: var(--color-accent-light);
|
||||
}
|
||||
</style>
|
||||
|
||||
<button class="button" on:click|preventDefault>
|
||||
<slot></slot>
|
||||
</button>
|
|
@ -1,15 +0,0 @@
|
|||
<button class="button" on:click>
|
||||
<slot></slot>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
.button {
|
||||
border: none;
|
||||
color: var(--color-text);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
outline-color: var(--color-accent-light);
|
||||
}
|
||||
</style>
|
|
@ -1,117 +1,117 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte/internal';
|
||||
import { c, s } from 'services/utils';
|
||||
import { onMount } from 'svelte/internal';
|
||||
import { c, s } from 'services/utils';
|
||||
|
||||
export let mode = 'h';
|
||||
export let basisFirst = 0.5;
|
||||
export let basisSecond = 0.5;
|
||||
export let minSize = 100;
|
||||
export let mode = 'h';
|
||||
export let basisFirst = 0.5;
|
||||
export let basisSecond = 0.5;
|
||||
export let minSize = 100;
|
||||
|
||||
let divide;
|
||||
let dragging = false;
|
||||
let size = 5;
|
||||
let total = 0;
|
||||
let divide;
|
||||
let dragging = false;
|
||||
let size = 5;
|
||||
let total = 0;
|
||||
|
||||
$: classes = c({
|
||||
divide: true,
|
||||
'divide--vertical': mode === 'v',
|
||||
});
|
||||
$: classes = c({
|
||||
divide: true,
|
||||
'divide--vertical': mode === 'v',
|
||||
});
|
||||
|
||||
$: classesDivider = c({
|
||||
divide__divider: true,
|
||||
'divide__divider--vertical': mode === 'v',
|
||||
});
|
||||
$: classesDivider = c({
|
||||
divide__divider: true,
|
||||
'divide__divider--vertical': mode === 'v',
|
||||
});
|
||||
|
||||
$: style = s({
|
||||
'--divide-size': `${size}px`,
|
||||
'--divide-basis-first': `${basisFirst * 100}%`,
|
||||
'--divide-basis-second': `${basisSecond * 100}%`,
|
||||
'--divide-min-width': minSize > 0 && mode === 'h' ? `${minSize}px` : '0',
|
||||
'--divide-min-height': minSize > 0 && mode === 'v' ? `${minSize}px` : '0',
|
||||
});
|
||||
$: style = s({
|
||||
'--divide-size': `${size}px`,
|
||||
'--divide-basis-first': `${basisFirst * 100}%`,
|
||||
'--divide-basis-second': `${basisSecond * 100}%`,
|
||||
'--divide-min-width': minSize > 0 && mode === 'h' ? `${minSize}px` : '0',
|
||||
'--divide-min-height': minSize > 0 && mode === 'v' ? `${minSize}px` : '0',
|
||||
});
|
||||
|
||||
function getTotal() {
|
||||
return mode === 'h' ? divide.clientWidth : divide.clientHeight;
|
||||
}
|
||||
|
||||
function handleMousedown(event) {
|
||||
if (event.button === 0) {
|
||||
dragging = true;
|
||||
total = getTotal();
|
||||
function getTotal() {
|
||||
return mode === 'h' ? divide.clientWidth : divide.clientHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMousemove(event) {
|
||||
if (dragging) {
|
||||
const dragPos =
|
||||
mode === 'h'
|
||||
? event.x - divide.getBoundingClientRect().x
|
||||
: event.y - divide.getBoundingClientRect().y;
|
||||
basisFirst = dragPos / total;
|
||||
basisSecond = 1 - basisFirst;
|
||||
function handleMousedown(event) {
|
||||
if (event.button === 0) {
|
||||
dragging = true;
|
||||
total = getTotal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseup() {
|
||||
dragging = false;
|
||||
}
|
||||
function handleMousemove(event) {
|
||||
if (dragging) {
|
||||
const dragPos =
|
||||
mode === 'h'
|
||||
? event.x - divide.getBoundingClientRect().x
|
||||
: event.y - divide.getBoundingClientRect().y;
|
||||
basisFirst = dragPos / total;
|
||||
basisSecond = 1 - basisFirst;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseenter(event) {
|
||||
if (event.buttons !== 1) {
|
||||
function handleMouseup() {
|
||||
dragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseenter(event) {
|
||||
if (event.buttons !== 1) {
|
||||
dragging = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.divide {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.divide {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.divide__divider {
|
||||
cursor: ew-resize;
|
||||
width: var(--divide-size);
|
||||
height: 100%;
|
||||
background-color: var(--color-foreground);
|
||||
}
|
||||
.divide__divider {
|
||||
cursor: ew-resize;
|
||||
width: var(--divide-size);
|
||||
height: 100%;
|
||||
background-color: var(--color-foreground);
|
||||
}
|
||||
|
||||
.divide__divider:hover {
|
||||
background-color: var(--color-foreground-light);
|
||||
}
|
||||
.divide__divider:hover {
|
||||
background-color: var(--color-foreground-light);
|
||||
}
|
||||
|
||||
.divide__elem {
|
||||
flex: 0 0 50%;
|
||||
min-width: var(--divide-min-width);
|
||||
max-width: calc(100% - var(--divide-size) - var(--divide-min-width));
|
||||
min-height: var(--divide-min-height);
|
||||
max-height: calc(100% - var(--divide-size) - var(--divide-min-height));
|
||||
}
|
||||
.divide__elem {
|
||||
flex: 0 0 50%;
|
||||
min-width: var(--divide-min-width);
|
||||
max-width: calc(100% - var(--divide-size) - var(--divide-min-width));
|
||||
min-height: var(--divide-min-height);
|
||||
max-height: calc(100% - var(--divide-size) - var(--divide-min-height));
|
||||
}
|
||||
|
||||
.divide__elem > :global(*) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.divide__elem > :global(*) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.divide__elem--first {
|
||||
flex-basis: calc(var(--divide-basis-first) - var(--divide-size) / 2);
|
||||
}
|
||||
.divide__elem--first {
|
||||
flex-basis: calc(var(--divide-basis-first) - var(--divide-size) / 2);
|
||||
}
|
||||
|
||||
.divide__elem--second {
|
||||
flex-basis: calc(var(--divide-basis-second) - var(--divide-size) / 2);
|
||||
}
|
||||
.divide__elem--second {
|
||||
flex-basis: calc(var(--divide-basis-second) - var(--divide-size) / 2);
|
||||
}
|
||||
|
||||
.divide--vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
.divide--vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.divide__divider--vertical {
|
||||
cursor: ns-resize;
|
||||
width: 100%;
|
||||
height: var(--divide-size);
|
||||
}
|
||||
.divide__divider--vertical {
|
||||
cursor: ns-resize;
|
||||
width: 100%;
|
||||
height: var(--divide-size);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import { ipcRenderer } from 'electron';
|
||||
|
||||
function sendCredentials(credentials: ICredentials) {
|
||||
function sendCredentials(credentials: ICredentials): void {
|
||||
ipcRenderer.send(IpcChannels.Credentials, credentials);
|
||||
}
|
||||
|
||||
ipcRenderer.on(IpcChannels.Pong, (event, ...args: any) => {
|
||||
console.log(args);
|
||||
});
|
||||
|
||||
export default {
|
||||
sendCredentials,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
export const enum Errors {
|
||||
ERROR = 'ERROR',
|
||||
ENOLOGIN = 'ENOLOGIN',
|
||||
ELOGINFAIL = 'ELOGINFAIL',
|
||||
}
|
||||
|
||||
const messages = {
|
||||
[Errors.ERROR]: 'error',
|
||||
[Errors.ENOLOGIN]: 'no login form found',
|
||||
[Errors.ELOGINFAIL]: 'login failed',
|
||||
};
|
||||
|
||||
export default class RenaiError extends Error {
|
||||
constructor(eno: Errors = Errors.ERROR, msg: string = '') {
|
||||
super(`Error ${eno}: ${messages[eno]}.${msg ? ` ${msg}` : ''}`);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
const enum IpcChannels {
|
||||
Credentials = 'CREDENTIALS',
|
||||
Pong = 'PONG',
|
||||
}
|
||||
|
||||
interface ICredentials {
|
||||
|
|
|
@ -20,11 +20,12 @@
|
|||
"no-floating-promises": true,
|
||||
"no-unused-expression": true,
|
||||
"await-promise": true,
|
||||
"no-inferrable-types": true,
|
||||
"no-inferrable-types": [true, "ignore-params", "ignore-properties"],
|
||||
"prefer-for-of": true,
|
||||
"no-empty": [true, "allow-empty-functions"],
|
||||
"no-magic-numbers": true,
|
||||
"no-parameter-reassignment": true
|
||||
"no-parameter-reassignment": true,
|
||||
"arrow-return-shorthand": true
|
||||
},
|
||||
"jsRules": true
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: {
|
||||
bundle: path.resolve(__dirname, 'src/renderer.ts'),
|
||||
},
|
||||
|
@ -33,6 +34,10 @@ module.exports = {
|
|||
alias: {
|
||||
atoms: path.resolve(__dirname, 'src/renderer/components/1-atoms'),
|
||||
molecules: path.resolve(__dirname, 'src/renderer/components/2-molecules'),
|
||||
polymers: path.resolve(__dirname, 'src/renderer/components/3-polymers'),
|
||||
cells: path.resolve(__dirname, 'src/renderer/components/4-cells'),
|
||||
organisms: path.resolve(__dirname, 'src/renderer/components/5-organisms'),
|
||||
templates: path.resolve(__dirname, 'src/renderer/components/6-templates'),
|
||||
services: path.resolve(__dirname, 'src/renderer/services'),
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue