Refactored with better posting rules
This commit is contained in:
parent
cf91fe1627
commit
75f099ce89
|
@ -70,14 +70,15 @@
|
|||
@click="hideSearch"><i class="fas fa-times"></i></a>
|
||||
</div>
|
||||
<div class="auto-ads" v-show="isAutopostingAds()">
|
||||
<h4>Auto-Posting Ads</h4>
|
||||
<h4>{{l('admgr.activeHeader')}}</h4>
|
||||
<div class="update">{{adAutoPostUpdate}}</div>
|
||||
|
||||
|
||||
<div v-show="adAutoPostNextAd" class="next">
|
||||
<h5>Coming Next</h5>
|
||||
<h5>{{l('admgr.comingNext')}}</h5>
|
||||
<div>{{(adAutoPostNextAd ? adAutoPostNextAd.substr(0, 50) : '')}}...</div>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-sm btn-outline-primary renew-autoposts" @click="renewAutoPosting()">{{l('admgr.renew')}}</a>
|
||||
</div>
|
||||
<div class="border-top messages" :class="isChannel(conversation) ? 'messages-' + conversation.mode : undefined" ref="messages"
|
||||
@scroll="onMessagesScroll" style="flex:1;overflow:auto;margin-top:2px">
|
||||
|
@ -117,15 +118,15 @@
|
|||
<ul class="nav nav-pills send-ads-switcher" v-if="isChannel(conversation)"
|
||||
style="position:relative;z-index:10;margin-right:5px">
|
||||
<li class="nav-item">
|
||||
<a href="#" :class="{active: !conversation.isSendingAds, disabled: conversation.channel.mode != 'both'}"
|
||||
<a href="#" :class="{active: !conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}"
|
||||
class="nav-link" @click.prevent="setSendingAds(false)">{{l('channel.mode.chat')}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" :class="{active: conversation.isSendingAds, disabled: conversation.channel.mode != 'both'}"
|
||||
<a href="#" :class="{active: conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}"
|
||||
class="nav-link" @click.prevent="setSendingAds(true)">{{adsMode}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" :class="{active: conversation.adState.active}" class="nav-link" @click="autoPostAds()">Auto-Post Ads</a>
|
||||
<a href="#" :class="{active: conversation.adManager.isActive()}" class="nav-link toggle-autopost" @click="toggleAutoPostAds()">{{l('admgr.toggleAutoPost')}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="btn btn-sm btn-primary" v-show="!settings.enterSend" @click="sendButton">{{l('chat.send')}}</div>
|
||||
|
@ -146,7 +147,7 @@
|
|||
import {Keys} from '../keys';
|
||||
import {BBCodeView, Editor} from './bbcode';
|
||||
import CommandHelp from './CommandHelp.vue';
|
||||
import { AdState, characterImage, getByteLength, getKey } from "./common";
|
||||
import { characterImage, getByteLength, getKey } from "./common";
|
||||
import ConversationSettings from './ConversationSettings.vue';
|
||||
import core from './core';
|
||||
import {Channel, channelModes, Character, Conversation, Settings} from './interfaces';
|
||||
|
@ -191,8 +192,8 @@
|
|||
adCountdown = 0;
|
||||
adsMode = l('channel.mode.ads');
|
||||
autoPostingUpdater = 0;
|
||||
adAutoPostUpdate: string|null = null;
|
||||
adAutoPostNextAd: string|null = null;
|
||||
adAutoPostUpdate: string | null = null;
|
||||
adAutoPostNextAd: string | null = null;
|
||||
isChannel = Conversation.isChannel;
|
||||
isPrivate = Conversation.isPrivate;
|
||||
|
||||
|
@ -236,7 +237,8 @@
|
|||
setAdCountdown();
|
||||
});
|
||||
|
||||
this.$watch('conversation.adState.active', () => (this.refreshAutoPostingTimer()));
|
||||
this.$watch(() => this.conversation.adManager.isActive(), () => (this.refreshAutoPostingTimer()));
|
||||
this.refreshAutoPostingTimer();
|
||||
}
|
||||
|
||||
@Hook('destroyed')
|
||||
|
@ -273,6 +275,7 @@
|
|||
if(!anyDialogsShown) (<Editor>this.$refs['textBox']).focus();
|
||||
this.$nextTick(() => setTimeout(() => this.messageView.scrollTop = this.messageView.scrollHeight));
|
||||
this.scrolledDown = true;
|
||||
this.refreshAutoPostingTimer();
|
||||
}
|
||||
|
||||
@Watch('conversation.messages')
|
||||
|
@ -399,78 +402,29 @@
|
|||
|
||||
|
||||
isAutopostingAds(): boolean {
|
||||
return this.conversation.adState.active;
|
||||
return this.conversation.adManager.isActive();
|
||||
}
|
||||
|
||||
|
||||
clearAutoPostAds(): void {
|
||||
if (this.conversation.adState.interval) {
|
||||
clearTimeout(this.conversation.adState.interval);
|
||||
}
|
||||
|
||||
this.conversation.adState = new AdState();
|
||||
stopAutoPostAds(): void {
|
||||
this.conversation.adManager.stop();
|
||||
}
|
||||
|
||||
|
||||
autoPostAds(): void {
|
||||
renewAutoPosting(): void {
|
||||
this.conversation.adManager.renew();
|
||||
|
||||
this.refreshAutoPostingTimer();
|
||||
}
|
||||
|
||||
|
||||
toggleAutoPostAds(): void {
|
||||
if(this.isAutopostingAds()) {
|
||||
this.clearAutoPostAds();
|
||||
this.refreshAutoPostingTimer();
|
||||
return;
|
||||
this.stopAutoPostAds();
|
||||
} else {
|
||||
this.conversation.adManager.start();
|
||||
}
|
||||
|
||||
const conversation = this.conversation;
|
||||
|
||||
/**** Do not use 'this' keyword below this line, it will operate differently than you expect ****/
|
||||
|
||||
const chanConv = (<Conversation.ChannelConversation>conversation);
|
||||
|
||||
const adState = conversation.adState;
|
||||
const initialWait = Math.max(0, chanConv.nextAd - Date.now()) * 1.1;
|
||||
|
||||
adState.adIndex = 0;
|
||||
|
||||
const sendNextPost = async () => {
|
||||
const ads = conversation.settings.adSettings.ads;
|
||||
const index = (adState.adIndex || 0);
|
||||
|
||||
if ((ads.length === 0) || ((adState.expireDue) && (adState.expireDue.getTime() < Date.now()))) {
|
||||
conversation.adState = new AdState();
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = ads[index % ads.length];
|
||||
|
||||
await chanConv.sendAd(msg);
|
||||
|
||||
const nextInMs = Math.max(0, (chanConv.nextAd - Date.now())) * 1.1;
|
||||
|
||||
adState.adIndex = index + 1;
|
||||
adState.nextPostDue = new Date(Date.now() + nextInMs);
|
||||
|
||||
adState.interval = setTimeout(
|
||||
async () => {
|
||||
await sendNextPost();
|
||||
},
|
||||
nextInMs
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
adState.active = true;
|
||||
adState.nextPostDue = new Date(Date.now() + initialWait);
|
||||
adState.expireDue = new Date(Date.now() + 2 * 60 * 60 * 1000);
|
||||
|
||||
|
||||
adState.interval = setTimeout(
|
||||
async () => {
|
||||
adState.firstPost = new Date();
|
||||
|
||||
await sendNextPost();
|
||||
},
|
||||
initialWait
|
||||
);
|
||||
|
||||
this.refreshAutoPostingTimer();
|
||||
}
|
||||
|
||||
|
@ -487,25 +441,28 @@
|
|||
}
|
||||
|
||||
const updateAutoPostingState = () => {
|
||||
const adState = this.conversation.adState;
|
||||
const ads = this.conversation.settings.adSettings.ads;
|
||||
const adManager = this.conversation.adManager;
|
||||
|
||||
if(ads.length > 0) {
|
||||
this.adAutoPostNextAd = ads[(adState.adIndex || 0) % ads.length];
|
||||
this.adAutoPostNextAd = adManager.getNextAd() || null;
|
||||
|
||||
const diff = ((adState.nextPostDue || new Date()).getTime() - Date.now()) / 1000;
|
||||
const expDiff = ((adState.expireDue || new Date()).getTime() - Date.now()) / 1000;
|
||||
if(this.adAutoPostNextAd) {
|
||||
const diff = ((adManager.getNextPostDue() || new Date()).getTime() - Date.now()) / 1000;
|
||||
const expDiff = ((adManager.getExpireDue() || new Date()).getTime() - Date.now()) / 1000;
|
||||
|
||||
if((adState.nextPostDue) && (!adState.firstPost)) {
|
||||
this.adAutoPostUpdate = `Posting beings in ${Math.floor(diff / 60)}m ${Math.floor(diff % 60)}s`;
|
||||
} else {
|
||||
this.adAutoPostUpdate = `Next ad in ${Math.floor(diff / 60)}m ${Math.floor(diff % 60)}s`;
|
||||
}
|
||||
const diffMins = Math.floor(diff / 60);
|
||||
const diffSecs = Math.floor(diff % 60);
|
||||
const expDiffMins = Math.floor(expDiff / 60);
|
||||
const expDiffSecs = Math.floor(expDiff % 60);
|
||||
|
||||
this.adAutoPostUpdate += `, auto-posting expires in ${Math.floor(expDiff / 60)}m ${Math.floor(expDiff % 60)}s`;
|
||||
this.adAutoPostUpdate = l(
|
||||
((adManager.getNextPostDue()) && (!adManager.getFirstPost())) ? 'admgr.postingBegins' : 'admgr.nextPostDue',
|
||||
diffMins,
|
||||
diffSecs
|
||||
) + l('admgr.expiresIn', expDiffMins, expDiffSecs);
|
||||
} else {
|
||||
this.adAutoPostNextAd = null;
|
||||
this.adAutoPostUpdate = 'No ads have been set up -- auto-posting will be cancelled.';
|
||||
|
||||
this.adAutoPostUpdate = l('admgr.noAds');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -514,7 +471,6 @@
|
|||
updateAutoPostingState();
|
||||
}
|
||||
|
||||
|
||||
hasSFC(message: Conversation.Message): message is Conversation.SFCMessage {
|
||||
return (<Partial<Conversation.SFCMessage>>message).sfc !== undefined;
|
||||
}
|
||||
|
@ -559,6 +515,12 @@
|
|||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
|
||||
.toggle-autopost {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
|
||||
.auto-ads {
|
||||
background-color: rgba(255, 128, 32, 0.8);
|
||||
padding-left: 10px;
|
||||
|
@ -566,6 +528,29 @@
|
|||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
|
||||
.renew-autoposts {
|
||||
display: block;
|
||||
float: right;
|
||||
/* margin-top: auto; */
|
||||
/* margin-bottom: auto; */
|
||||
position: absolute;
|
||||
/* bottom: 1px; */
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.1rem;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {WebSocketConnection} from '../fchat';
|
||||
|
||||
export default class Socket implements WebSocketConnection {
|
||||
static host = 'wss://chat.f-list.net:9799';
|
||||
static host = 'wss://chat.f-list.net/chat2';
|
||||
private socket: WebSocket;
|
||||
private lastHandler: Promise<void> = Promise.resolve();
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import { Conversation } from './interfaces';
|
||||
|
||||
export class AdManager {
|
||||
static readonly POSTING_PERIOD = 3 * 60 * 60 * 1000;
|
||||
static readonly START_VARIANCE = 3 * 60 * 1000;
|
||||
static readonly POST_VARIANCE = 10 * 60 * 1000;
|
||||
static readonly POST_DELAY = 2 * 60 * 1000;
|
||||
|
||||
private conversation: Conversation;
|
||||
|
||||
private adIndex = 0;
|
||||
private active = false;
|
||||
private nextPostDue?: Date;
|
||||
private expireDue?: Date;
|
||||
private firstPost?: Date;
|
||||
private interval?: any;
|
||||
|
||||
constructor(conversation: Conversation) {
|
||||
this.conversation = conversation;
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
private async sendNextPost(): Promise<void> {
|
||||
const msg = this.getNextAd();
|
||||
|
||||
if ((!msg) || ((this.expireDue) && (this.expireDue.getTime() < Date.now()))) {
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
const chanConv = (<Conversation.ChannelConversation>this.conversation);
|
||||
|
||||
await chanConv.sendAd(msg);
|
||||
|
||||
// post next ad every 12 - 22 minutes
|
||||
const nextInMs = Math.max(0, (chanConv.nextAd - Date.now())) +
|
||||
AdManager.POST_DELAY +
|
||||
Math.random() * AdManager.POST_VARIANCE;
|
||||
|
||||
this.adIndex = this.adIndex + 1;
|
||||
this.nextPostDue = new Date(Date.now() + nextInMs);
|
||||
|
||||
this.interval = setTimeout(
|
||||
async() => {
|
||||
await this.sendNextPost();
|
||||
},
|
||||
nextInMs
|
||||
);
|
||||
}
|
||||
|
||||
getAds(): string[] {
|
||||
return this.conversation.settings.adSettings.ads;
|
||||
}
|
||||
|
||||
getNextAd(): string | undefined {
|
||||
const ads = this.getAds();
|
||||
|
||||
if (ads.length === 0)
|
||||
return;
|
||||
|
||||
return ads[this.adIndex % ads.length];
|
||||
}
|
||||
|
||||
getNextPostDue(): Date | undefined {
|
||||
return this.nextPostDue;
|
||||
}
|
||||
|
||||
getExpireDue(): Date | undefined {
|
||||
return this.expireDue;
|
||||
}
|
||||
|
||||
getFirstPost(): Date | undefined {
|
||||
return this.firstPost;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
const chanConv = (<Conversation.ChannelConversation>this.conversation);
|
||||
const initialWait = Math.max(Math.random() * AdManager.START_VARIANCE, (chanConv.nextAd - Date.now()) * 1.1);
|
||||
|
||||
this.adIndex = 0;
|
||||
this.active = true;
|
||||
this.nextPostDue = new Date(Date.now() + initialWait);
|
||||
this.expireDue = new Date(Date.now() + AdManager.POSTING_PERIOD);
|
||||
|
||||
this.interval = setTimeout(
|
||||
async() => {
|
||||
this.firstPost = new Date();
|
||||
|
||||
await this.sendNextPost();
|
||||
},
|
||||
initialWait
|
||||
);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (this.interval)
|
||||
clearTimeout(this.interval);
|
||||
|
||||
delete this.interval;
|
||||
delete this.nextPostDue;
|
||||
delete this.expireDue;
|
||||
delete this.firstPost;
|
||||
|
||||
this.active = false;
|
||||
this.adIndex = 0;
|
||||
|
||||
// const message = new EventMessage(`Advertisements on channel [channel]${this.conversation.name}[/channel] have expired.`);
|
||||
// addEventMessage(message);
|
||||
}
|
||||
|
||||
renew(): void {
|
||||
if (!this.active)
|
||||
return;
|
||||
|
||||
this.expireDue = new Date(Date.now() + 3 * 60 * 60 * 1000);
|
||||
}
|
||||
}
|
|
@ -50,16 +50,6 @@ export class AdSettings implements Conversation.AdSettings {
|
|||
}
|
||||
|
||||
|
||||
export class AdState implements Conversation.AdState {
|
||||
active = false;
|
||||
firstPost?: Date = undefined;
|
||||
nextPostDue?: Date = undefined;
|
||||
interval?: any = undefined;
|
||||
adIndex?: number = undefined;
|
||||
expireDue?: Date = undefined;
|
||||
}
|
||||
|
||||
|
||||
export class ConversationSettings implements Conversation.Settings {
|
||||
notify = Conversation.Setting.Default;
|
||||
highlight = Conversation.Setting.Default;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {queuedJoin} from '../fchat/channels';
|
||||
import {decodeHTML} from '../fchat/common';
|
||||
import { AdState, characterImage, ConversationSettings, EventMessage, Message, messageToString } from './common';
|
||||
import { AdManager } from './ad-manager';
|
||||
import { characterImage, ConversationSettings, EventMessage, Message, messageToString } from './common';
|
||||
import core from './core';
|
||||
import {Channel, Character, Conversation as Interfaces} from './interfaces';
|
||||
import l from './localize';
|
||||
|
@ -30,14 +31,15 @@ abstract class Conversation implements Interfaces.Conversation {
|
|||
infoText = '';
|
||||
abstract readonly maxMessageLength: number | undefined;
|
||||
_settings: Interfaces.Settings | undefined;
|
||||
_adState: Interfaces.AdState | undefined;
|
||||
protected abstract context: CommandContext;
|
||||
protected maxMessages = 50;
|
||||
protected allMessages: Interfaces.Message[] = [];
|
||||
readonly reportMessages: Interfaces.Message[] = [];
|
||||
private lastSent = '';
|
||||
adManager: AdManager;
|
||||
|
||||
constructor(readonly key: string, public _isPinned: boolean) {
|
||||
this.adManager = new AdManager(this);
|
||||
}
|
||||
|
||||
get settings(): Interfaces.Settings {
|
||||
|
@ -50,17 +52,6 @@ abstract class Conversation implements Interfaces.Conversation {
|
|||
state.setSettings(this.key, value); //tslint:disable-line:no-floating-promises
|
||||
}
|
||||
|
||||
get adState(): Interfaces.AdState {
|
||||
//tslint:disable-next-line:strict-boolean-expressions
|
||||
return this._adState || (this._adState = state.adStates[this.key] || new AdState());
|
||||
}
|
||||
|
||||
set adState(value: Interfaces.AdState) {
|
||||
this._adState = value;
|
||||
state.setAdState(this.key, value); //tslint:disable-line:no-floating-promises
|
||||
}
|
||||
|
||||
|
||||
get isPinned(): boolean {
|
||||
return this._isPinned;
|
||||
}
|
||||
|
@ -200,12 +191,11 @@ class PrivateConversation extends Conversation implements Interfaces.PrivateConv
|
|||
return;
|
||||
}
|
||||
|
||||
if(this.adState.active) {
|
||||
if(this.adManager.isActive()) {
|
||||
this.errorText = 'Cannot send ads manually while ad auto-posting is active';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
core.connection.send('PRI', {recipient: this.name, message: this.enteredText});
|
||||
const message = createMessage(MessageType.Message, core.characters.ownCharacter, this.enteredText);
|
||||
this.safeAddMessage(message);
|
||||
|
@ -331,7 +321,7 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv
|
|||
protected async doSend(): Promise<void> {
|
||||
const isAd = this.isSendingAds;
|
||||
|
||||
if(this.adState.active) {
|
||||
if(this.adManager.isActive()) {
|
||||
this.errorText = 'Cannot post ads manually while ad auto-posting is active';
|
||||
return;
|
||||
}
|
||||
|
@ -349,7 +339,6 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv
|
|||
else this.clearText();
|
||||
}
|
||||
|
||||
|
||||
async sendAd(text: string): Promise<void> {
|
||||
if (text.length < 1)
|
||||
return;
|
||||
|
@ -399,7 +388,6 @@ class State implements Interfaces.State {
|
|||
recentChannels: Interfaces.RecentChannelConversation[] = [];
|
||||
pinned!: {channels: string[], private: string[]};
|
||||
settings!: {[key: string]: Interfaces.Settings};
|
||||
adStates: {[key: string]: Interfaces.AdState} = {};
|
||||
modes!: {[key: string]: Channel.Mode | undefined};
|
||||
windowFocused = document.hasFocus();
|
||||
|
||||
|
@ -444,12 +432,6 @@ class State implements Interfaces.State {
|
|||
await core.settingsStore.set('conversationSettings', this.settings);
|
||||
}
|
||||
|
||||
|
||||
setAdState(key: string, value: Interfaces.AdState): void {
|
||||
this.adStates[key] = value;
|
||||
}
|
||||
|
||||
|
||||
show(conversation: Conversation): void {
|
||||
this.selectedConversation.onHide();
|
||||
conversation.unread = Interfaces.UnreadState.None;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import {Connection} from '../fchat';
|
||||
|
||||
import {Channel, Character} from '../fchat/interfaces';
|
||||
import { AdManager } from './ad-manager';
|
||||
export {Connection, Channel, Character} from '../fchat/interfaces';
|
||||
export const userStatuses: ReadonlyArray<Character.Status> = ['online', 'looking', 'away', 'busy', 'dnd'];
|
||||
export const channelModes: ReadonlyArray<Channel.Mode> = ['chat', 'ads', 'both'];
|
||||
|
@ -98,22 +99,10 @@ export namespace Conversation {
|
|||
readonly adSettings: AdSettings;
|
||||
}
|
||||
|
||||
|
||||
export interface AdSettings {
|
||||
readonly ads: string[];
|
||||
}
|
||||
|
||||
|
||||
export interface AdState {
|
||||
active: boolean;
|
||||
firstPost?: Date;
|
||||
nextPostDue?: Date;
|
||||
expireDue?: Date;
|
||||
interval?: any;
|
||||
adIndex?: number;
|
||||
}
|
||||
|
||||
|
||||
export const enum UnreadState { None, Unread, Mention }
|
||||
|
||||
export interface Conversation {
|
||||
|
@ -127,7 +116,7 @@ export namespace Conversation {
|
|||
readonly key: string
|
||||
readonly unread: UnreadState
|
||||
settings: Settings
|
||||
adState: AdState
|
||||
readonly adManager: AdManager;
|
||||
send(): Promise<void>
|
||||
clear(): void
|
||||
loadLastSent(): void
|
||||
|
|
|
@ -17,6 +17,14 @@ const strings: {[key: string]: string | undefined} = {
|
|||
'action.updateAvailable': 'UPDATE AVAILABLE',
|
||||
'action.update': 'Restart now!',
|
||||
'action.cancel': 'Cancel',
|
||||
'admgr.postingBegins': 'Posting beings in {0}m {1}s',
|
||||
'admgr.nextPostDue': 'Next ad in {0}m {1}s',
|
||||
'admgr.expiresIn': ', auto-posting expires in {0}m {1}s',
|
||||
'admgr.noAds': 'No ads have been set up -- auto-posting will be cancelled.',
|
||||
'admgr.activeHeader': 'Auto-Posting Ads',
|
||||
'admgr.comingNext': 'Coming Next',
|
||||
'admgr.renew': 'Renew',
|
||||
'admgr.toggleAutoPost': 'Auto-Post Ads',
|
||||
'consoleWarning.head': 'THIS IS THE DANGER ZONE.',
|
||||
'consoleWarning.body': `ANYTHING YOU WRITE OR PASTE IN HERE COULD BE USED TO STEAL YOUR PASSWORDS OR TAKE OVER YOUR ENTIRE COMPUTER. This is where happiness goes to die. If you aren't a developer or a special kind of daredevil, please get out of here!`,
|
||||
'help': 'Help',
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"module": "commonjs",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"noEmitHelpers": true,
|
||||
"importHelpers": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
},
|
||||
"include": ["./electron/main.ts"]
|
||||
}
|
Loading…
Reference in New Issue