diff --git a/src/api.ts b/src/api.ts index c105f27..a26c1da 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,3 +1,8 @@ +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { Resolve } from '@angular/router' +import { Observable } from 'rxjs' + export interface User { active_config: number active_version: string @@ -17,3 +22,16 @@ export interface Config { export interface Version { version: string } + +export interface InstanceInfo { + login_enabled: boolean +} + +@Injectable({ providedIn: 'root' }) +export class InstanceInfoResolver implements Resolve> { + constructor (private http: HttpClient) { } + + resolve(): Observable { + return this.http.get('/api/1/instance-info').toPromise() + } +} diff --git a/src/app.module.ts b/src/app.module.ts index a8117d8..cbf5bdd 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -13,11 +13,30 @@ import { ConfigModalComponent } from './components/configModal.component' import { SettingsModalComponent } from './components/settingsModal.component' import { HomeComponent } from './components/home.component' import { LoginComponent } from './components/login.component' +import { InstanceInfoResolver } from './api' const ROUTES = [ - { path: '', component: HomeComponent }, - { path: 'app', component: MainComponent }, - { path: 'login', component: LoginComponent }, + { + path: '', + component: HomeComponent, + resolve: { + instanceInfo: InstanceInfoResolver, + } + }, + { + path: 'app', + component: MainComponent, + resolve: { + instanceInfo: InstanceInfoResolver, + } + }, + { + path: 'login', + component: LoginComponent, + resolve: { + instanceInfo: InstanceInfoResolver, + } + }, ] @NgModule({ diff --git a/src/assets/screenshots/win.png b/src/assets/screenshots/win.png new file mode 100644 index 0000000..d8e4784 Binary files /dev/null and b/src/assets/screenshots/win.png differ diff --git a/src/components/home.component.pug b/src/components/home.component.pug index b440cbd..ee721d2 100644 --- a/src/components/home.component.pug +++ b/src/components/home.component.pug @@ -5,7 +5,10 @@ a.btn.btn-primary([href]='releaseURL', target='_blank') fa-icon([icon]='_downloadIcon', [fixedWidth]='true') span Download - a.btn.btn-secondary(routerLink='/login') + a.btn.btn-secondary([href]='donationURL', target='_blank') + fa-icon([icon]='_donateIcon', [fixedWidth]='true') + span Donate + a.btn.btn-secondary(routerLink='/login', *ngIf='instanceInfo.login_enabled') fa-icon([icon]='_loginIcon', [fixedWidth]='true') span Login @@ -84,7 +87,7 @@ .col img.screenshot([src]='screenshots.ssh') .col - h1 SSH + h1 SSH Client ul li SSH2 client with a connection manager li #[strong SFTP and Zmodem] file transfers @@ -94,3 +97,47 @@ li Login scripts li Optional built-in #[strong password manager] with a master passphrase li #[strong Proxy command] support + + .section.section-b + .container + .row + .col + h1 Windows, but nice + ul + li Support for #[strong different shells] in the same window + li Better tab completion #[strong cmd.exe] thanks to Clink. + li Explorer menu integration + li Optional #[strong portable mode] + li Current directory detection that works + .col + img.screenshot([src]='screenshots.win') + + .section.section-a + .container + .row + .col + img.screenshot([src]='screenshots.serial') + .col + h1 Serial Terminal + ul + li Multiple #[strong connection profiles] + li Newline conversion + li Text, #[strong readline] and #[strong byte-by-byte] input modes + li Text and #[strong hexdump] output modes + li Zmodem + li Non-standard baud rates + + .section.section-a + .container + h1 And just too much stuff to mention here: + ul + li Themes #[strong customizable with CSS] + li Extensible via #[strong plugins] (in JS) + li A bunch of color schemes already included + li #[strong Font ligatures] and font fallback + li #[strong Clickable URLs], IPs and paths + li #[strong WinSCP] integration + li Shell #[strong profiles] + li Simultaneous #[strong multi-pane input] + li Optional PuTTY style #[strong right-click paste] and #[strong copy on select] + li macOS vibrancy and Win 10 fluent background support diff --git a/src/components/home.component.scss b/src/components/home.component.scss index a7c508f..aca4903 100644 --- a/src/components/home.component.scss +++ b/src/components/home.component.scss @@ -52,7 +52,7 @@ iframe { } .quotes { - margin: 30px 0; + margin: 50px 0; display: flex; justify-content: center; text-align: center; @@ -79,7 +79,7 @@ strong { } .section { - padding: 30px 0; + padding: 50px 0; .screenshot { min-width: 0; diff --git a/src/components/home.component.ts b/src/components/home.component.ts index 468401f..fa609df 100644 --- a/src/components/home.component.ts +++ b/src/components/home.component.ts @@ -1,9 +1,10 @@ import * as semverGT from 'semver/functions/gt' import { HttpClient } from '@angular/common/http' import { Component, ElementRef, ViewChild } from '@angular/core' -import { Version } from '../api' -import { faDownload, faSignInAlt } from '@fortawesome/free-solid-svg-icons' +import { InstanceInfo, Version } from '../api' +import { faCoffee, faDownload, faSignInAlt } from '@fortawesome/free-solid-svg-icons' import { faGithub } from '@fortawesome/free-brands-svg-icons' +import { ActivatedRoute } from '@angular/router' class DemoConnector { constructor (targetWindow: Window, private version: Version) { @@ -47,18 +48,30 @@ export class HomeComponent { connector: DemoConnector githubURL = 'https://github.com/Eugeny/terminus' releaseURL = `${this.githubURL}/releases/latest` + donationURL = 'https://ko-fi.com/eugeny' + _logo = require('../assets/logo.svg') _downloadIcon = faDownload _loginIcon = faSignInAlt _githubIcon = faGithub + _donateIcon = faCoffee + screenshots = { window: require('../assets/screenshots/window.png'), tabs: require('../assets/screenshots/tabs.png'), ssh: require('../assets/screenshots/ssh.png'), + serial: require('../assets/screenshots/serial.png'), + win: require('../assets/screenshots/win.png'), } - constructor (private http: HttpClient) { + instanceInfo: InstanceInfo + + constructor ( + private http: HttpClient, + route: ActivatedRoute, + ) { window.addEventListener('message', this.connectorRequestHandler) + this.instanceInfo = route.snapshot.data.instanceInfo } connectorRequestHandler = event => { diff --git a/terminus/app/api.py b/terminus/app/api.py index 545c193..b6c64a2 100644 --- a/terminus/app/api.py +++ b/terminus/app/api.py @@ -9,7 +9,7 @@ from rest_framework.response import Response from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet, ModelViewSet -from rest_framework.serializers import ModelSerializer +from rest_framework.serializers import ModelSerializer, Serializer from rest_framework_dataclasses.serializers import DataclassSerializer from .models import Config, User @@ -89,3 +89,17 @@ class LogoutView(APIView): def post(self, request, format=None): logout(request) return Response(None) + + +class InstanceInfoSerializer(Serializer): + login_enabled = fields.BooleanField() + + +class InstanceInfoViewSet(RetrieveModelMixin, GenericViewSet): + queryset = '' # type: ignore + serializer_class = InstanceInfoSerializer + + def get_object(self): + return { + 'login_enabled': settings.ENABLE_LOGIN, + } diff --git a/terminus/app/urls.py b/terminus/app/urls.py index 1cb30b8..b934f87 100644 --- a/terminus/app/urls.py +++ b/terminus/app/urls.py @@ -13,6 +13,7 @@ router.register('api/1/versions', api.AppVersionViewSet, basename='app-versions' urlpatterns = [ path('api/1/auth/logout', api.LogoutView.as_view()), path('api/1/user', api.UserViewSet.as_view({'get': 'retrieve', 'put': 'update'})), + path('api/1/instance-info', api.InstanceInfoViewSet.as_view({'get': 'retrieve'})), re_path('^(|login|app)$', views.IndexView.as_view()), diff --git a/terminus/settings.py b/terminus/settings.py index 3a5cde1..a36aac6 100644 --- a/terminus/settings.py +++ b/terminus/settings.py @@ -157,6 +157,7 @@ for key in [ 'GITHUB_SPONSORS_USER', 'GITHUB_SPONSORS_MIN_PAYMENT', 'GITHUB_TOKEN', + 'ENABLE_LOGIN', ]: globals()[key] = os.getenv(key)