project rename

This commit is contained in:
Eugene Pankov
2021-06-29 23:57:04 +02:00
parent c61be3d52b
commit 43cd3318da
609 changed files with 510 additions and 530 deletions

View File

@@ -0,0 +1,13 @@
.modal-body
div {{options.message}}
small {{options.detail}}
.modal-footer
.ml-auto
button.btn(
*ngFor='let button of options.buttons; index as i',
[autofocus]='i === options.defaultId',
[class.btn-primary]='i === options.defaultId',
[class.btn-secondary]='i !== options.defaultId',
(click)='onButton(i)',
) {{button}}

View File

@@ -0,0 +1,34 @@
import { Component, Input, ElementRef } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { BaseComponent, HotkeysService, MessageBoxOptions } from 'tabby-core'
/** @hidden */
@Component({
template: require('./messageBoxModal.component.pug'),
})
export class MessageBoxModalComponent extends BaseComponent {
@Input() options: MessageBoxOptions
constructor (
hotkeys: HotkeysService,
private element: ElementRef,
private modalInstance: NgbActiveModal,
) {
super()
this.subscribeUntilDestroyed(hotkeys.key, (event: KeyboardEvent) => {
if (event.type === 'keydown') {
if (event.key === 'Enter' && this.options.defaultId !== undefined) {
this.modalInstance.close(this.options.defaultId)
}
}
})
}
ngAfterViewInit (): void {
this.element.nativeElement.querySelector('button[autofocus]').focus()
}
onButton (index: number): void {
this.modalInstance.close(index)
}
}

32
tabby-web/src/index.ts Normal file
View File

@@ -0,0 +1,32 @@
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { HostAppService, HostWindowService, LogService, PlatformService, UpdaterService } from 'tabby-core'
import { WebPlatformService } from './platform'
import { ConsoleLogService } from './services/log.service'
import { NullUpdaterService } from './services/updater.service'
import { WebHostWindow } from './services/hostWindow.service'
import { WebHostApp } from './services/hostApp.service'
import { MessageBoxModalComponent } from './components/messageBoxModal.component'
import './styles.scss'
@NgModule({
imports: [
CommonModule,
],
providers: [
{ provide: PlatformService, useClass: WebPlatformService },
{ provide: LogService, useClass: ConsoleLogService },
{ provide: UpdaterService, useClass: NullUpdaterService },
{ provide: HostWindowService, useClass: WebHostWindow },
{ provide: HostAppService, useClass: WebHostApp },
],
declarations: [
MessageBoxModalComponent,
],
entryComponents: [
MessageBoxModalComponent,
],
})
export default class WebModule { } // eslint-disable-line @typescript-eslint/no-extraneous-class

182
tabby-web/src/platform.ts Normal file
View File

@@ -0,0 +1,182 @@
import '@vaadin/vaadin-context-menu'
import copyToClipboard from 'copy-text-to-clipboard'
import { Injectable, Inject } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { PlatformService, ClipboardContent, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileUploadOptions, FileDownload, HTMLFileUpload } from 'tabby-core'
// eslint-disable-next-line no-duplicate-imports
import type { ContextMenuElement, ContextMenuItem } from '@vaadin/vaadin-context-menu'
import { MessageBoxModalComponent } from './components/messageBoxModal.component'
import './styles.scss'
@Injectable()
export class WebPlatformService extends PlatformService {
private menu: ContextMenuElement
private contextMenuHandlers = new Map<ContextMenuItem, () => void>()
private fileSelector: HTMLInputElement
constructor (
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
@Inject('WEB_CONNECTOR') private connector: any,
private ngbModal: NgbModal,
) {
super()
this.menu = window.document.createElement('vaadin-context-menu')
this.menu.addEventListener('item-selected', e => {
this.contextMenuHandlers.get(e.detail.value)?.()
})
document.body.appendChild(this.menu)
this.fileSelector = document.createElement('input')
this.fileSelector.type = 'file'
this.fileSelector.style.visibility = 'hidden'
document.body.appendChild(this.fileSelector)
}
readClipboard (): string {
return ''
}
setClipboard (content: ClipboardContent): void {
copyToClipboard(content.text)
}
async loadConfig (): Promise<string> {
return this.connector.loadConfig()
}
async saveConfig (content: string): Promise<void> {
await this.connector.saveConfig(content)
}
getOSRelease (): string {
return '1.0'
}
openExternal (url: string): void {
window.open(url)
}
getAppVersion (): string {
return this.connector.getAppVersion()
}
async listFonts (): Promise<string[]> {
return []
}
popupContextMenu (menu: MenuItemOptions[], event?: MouseEvent): void {
this.contextMenuHandlers.clear()
this.menu.items = menu
.filter(x => x.type !== 'separator')
.map(x => this.remapMenuItem(x))
setTimeout(() => {
this.menu.open(event)
}, 10)
}
private remapMenuItem (item: MenuItemOptions): ContextMenuItem {
const cmi = {
text: item.label,
disabled: !(item.enabled ?? true),
checked: item.checked,
children: item.submenu?.map(i => this.remapMenuItem(i)),
}
if (item.click) {
this.contextMenuHandlers.set(cmi, item.click)
}
return cmi
}
async showMessageBox (options: MessageBoxOptions): Promise<MessageBoxResult> {
console.log(options)
const modal = this.ngbModal.open(MessageBoxModalComponent, {
backdrop: 'static',
})
const instance: MessageBoxModalComponent = modal.componentInstance
instance.options = options
try {
const response = await modal.result
return { response }
} catch {
return { response: 0 }
}
}
quit (): void {
window.close()
}
async startDownload (name: string, size: number): Promise<FileDownload|null> {
const transfer = new HTMLFileDownload(name, size)
this.fileTransferStarted.next(transfer)
return transfer
}
startUpload (options?: FileUploadOptions): Promise<FileUpload[]> {
return new Promise(resolve => {
this.fileSelector.onchange = () => {
const transfers: FileUpload[] = []
const fileList = this.fileSelector.files!
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
for (let i = 0; i < (fileList.length ?? 0); i++) {
const file = fileList[i]
const transfer = new HTMLFileUpload(file)
this.fileTransferStarted.next(transfer)
transfers.push(transfer)
if (!options?.multiple) {
break
}
}
resolve(transfers)
}
this.fileSelector.click()
})
}
setErrorHandler (handler: (_: any) => void): void {
window.addEventListener('error', handler)
}
}
class HTMLFileDownload extends FileDownload {
private buffers: Buffer[] = []
constructor (
private name: string,
private size: number,
) {
super()
}
getName (): string {
return this.name
}
getSize (): number {
return this.size
}
async write (buffer: Buffer): Promise<void> {
this.buffers.push(Buffer.from(buffer))
this.increaseProgress(buffer.length)
if (this.isComplete()) {
this.finish()
}
}
finish () {
const blob = new Blob(this.buffers, { type: 'application/octet-stream' })
const element = window.document.createElement('a')
element.href = window.URL.createObjectURL(blob)
element.download = this.name
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
close (): void { }
}

View File

@@ -0,0 +1,33 @@
import { Injectable, Injector } from '@angular/core'
import { HostAppService, Platform } from 'tabby-core'
@Injectable()
export class WebHostApp extends HostAppService {
get platform (): Platform {
return Platform.Web
}
get configPlatform (): Platform {
return Platform.Windows // TODO
}
// Needed for injector metadata
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor (
injector: Injector,
) {
super(injector)
}
newWindow (): void {
throw new Error('Not implemented')
}
relaunch (): void {
location.reload()
}
quit (): void {
window.close()
}
}

View File

@@ -0,0 +1,45 @@
import { Injectable } from '@angular/core'
import { HostWindowService } from 'tabby-core'
@Injectable({ providedIn: 'root' })
export class WebHostWindow extends HostWindowService {
get isFullscreen (): boolean { return !!document.fullscreenElement }
constructor () {
super()
this.windowShown.next()
this.windowFocused.next()
}
reload (): void {
location.reload()
}
setTitle (title?: string): void {
document.title = title ?? 'Tabby'
}
toggleFullscreen (): void {
if (this.isFullscreen) {
document.exitFullscreen()
} else {
document.body.requestFullscreen({ navigationUI: 'hide' })
}
}
minimize (): void {
throw new Error('Unavailable')
}
isMaximized (): boolean {
return true
}
toggleMaximize (): void {
throw new Error('Unavailable')
}
close (): void {
window.close()
}
}

View File

@@ -0,0 +1,9 @@
import { Injectable } from '@angular/core'
import { ConsoleLogger, Logger } from 'tabby-core'
@Injectable({ providedIn: 'root' })
export class ConsoleLogService {
create (name: string): Logger {
return new ConsoleLogger(name)
}
}

View File

@@ -0,0 +1,10 @@
import { UpdaterService } from 'tabby-core'
export class NullUpdaterService extends UpdaterService {
async check (): Promise<boolean> {
return false
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
async update (): Promise<void> { }
}

11
tabby-web/src/styles.scss Normal file
View File

@@ -0,0 +1,11 @@
@import "../../tabby-core/src/theme.vars.scss";
html.tabby {
--lumo-primary-text-color: #{$body-color};
--lumo-base-color: #{$body-bg};
--lumo-body-text-color: #{$body-color};
--lumo-tint-5pct: #{$body-bg};
--lumo-font-family: #{$font-family-sans-serif};
--lumo-font-size-m: #{$font-size-base};
--lumo-box-shadow-m: #{$dropdown-box-shadow};
}