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