mirror of
https://github.com/Eugeny/tabby.git
synced 2025-09-18 06:14:37 +00:00
project rename
This commit is contained in:
13
tabby-web/src/components/messageBoxModal.component.pug
Normal file
13
tabby-web/src/components/messageBoxModal.component.pug
Normal 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}}
|
34
tabby-web/src/components/messageBoxModal.component.ts
Normal file
34
tabby-web/src/components/messageBoxModal.component.ts
Normal 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
32
tabby-web/src/index.ts
Normal 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
182
tabby-web/src/platform.ts
Normal 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 { }
|
||||
}
|
33
tabby-web/src/services/hostApp.service.ts
Normal file
33
tabby-web/src/services/hostApp.service.ts
Normal 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()
|
||||
}
|
||||
}
|
45
tabby-web/src/services/hostWindow.service.ts
Normal file
45
tabby-web/src/services/hostWindow.service.ts
Normal 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()
|
||||
}
|
||||
}
|
9
tabby-web/src/services/log.service.ts
Normal file
9
tabby-web/src/services/log.service.ts
Normal 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)
|
||||
}
|
||||
}
|
10
tabby-web/src/services/updater.service.ts
Normal file
10
tabby-web/src/services/updater.service.ts
Normal 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
11
tabby-web/src/styles.scss
Normal 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};
|
||||
}
|
Reference in New Issue
Block a user