mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-03 09:49:20 +02:00
Add ability to set square icon in welcome wizard
This commit is contained in:
parent
37da276f9c
commit
c9905ecd3a
11 changed files with 53 additions and 15 deletions
|
@ -16,7 +16,7 @@ import {
|
||||||
import { AdminConfigCustomizationComponent } from './pages/admin-config-customization.component'
|
import { AdminConfigCustomizationComponent } from './pages/admin-config-customization.component'
|
||||||
import { AdminConfigService } from '../../shared/shared-admin/admin-config.service'
|
import { AdminConfigService } from '../../shared/shared-admin/admin-config.service'
|
||||||
import { AdminConfigLogoComponent } from './pages/admin-config-logo.component'
|
import { AdminConfigLogoComponent } from './pages/admin-config-logo.component'
|
||||||
import { InstanceLogoService } from './shared/instance-logo.service'
|
import { InstanceLogoService } from '../../shared/shared-instance/instance-logo.service'
|
||||||
|
|
||||||
export const customConfigResolver: ResolveFn<CustomConfig> = (_route: ActivatedRouteSnapshot, _state: RouterStateSnapshot) => {
|
export const customConfigResolver: ResolveFn<CustomConfig> = (_route: ActivatedRouteSnapshot, _state: RouterStateSnapshot) => {
|
||||||
return inject(AdminConfigService).getCustomConfig()
|
return inject(AdminConfigService).getCustomConfig()
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { of, Subscription, switchMap, tap } from 'rxjs'
|
||||||
import { AdminConfigService } from '../../../shared/shared-admin/admin-config.service'
|
import { AdminConfigService } from '../../../shared/shared-admin/admin-config.service'
|
||||||
import { PreviewUploadComponent } from '../../../shared/shared-forms/preview-upload.component'
|
import { PreviewUploadComponent } from '../../../shared/shared-forms/preview-upload.component'
|
||||||
import { AdminSaveBarComponent } from '../shared/admin-save-bar.component'
|
import { AdminSaveBarComponent } from '../shared/admin-save-bar.component'
|
||||||
import { InstanceLogoService } from '../shared/instance-logo.service'
|
import { InstanceLogoService } from '../../../shared/shared-instance/instance-logo.service'
|
||||||
|
|
||||||
type Form = {
|
type Form = {
|
||||||
hideInstanceName: FormControl<boolean>
|
hideInstanceName: FormControl<boolean>
|
||||||
|
|
|
@ -225,7 +225,7 @@
|
||||||
<div class="content-col">
|
<div class="content-col">
|
||||||
|
|
||||||
<div class="danger-zone">
|
<div class="danger-zone">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="mb-1 fw-bold" i18n>Send a link to reset the password by email to the user</div>
|
<div class="mb-1 fw-bold" i18n>Send a link to reset the password by email to the user</div>
|
||||||
<button class="peertube-button danger-button" (click)="resetPassword()" i18n>Ask for new password</button>
|
<button class="peertube-button danger-button" (click)="resetPassword()" i18n>Ask for new password</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||||
import { AdminConfigWizardStepperComponent } from './admin-config-wizard-stepper.component'
|
import { AdminConfigWizardStepperComponent } from './admin-config-wizard-stepper.component'
|
||||||
import { getNoWelcomeModalLocalStorageKey } from './shared/admin-config-wizard-modal-utils'
|
import { getNoWelcomeModalLocalStorageKey } from './shared/admin-config-wizard-modal-utils'
|
||||||
import { AdminConfigWizardDocumentationComponent } from './steps/admin-config-wizard-documentation.component'
|
import { AdminConfigWizardDocumentationComponent } from './steps/admin-config-wizard-documentation.component'
|
||||||
import { AdminConfigWizardEditInfoComponent, FormInfo } from './steps/admin-config-wizard-edit-info.component'
|
import { AdminConfigWizardEditInfoComponent, FormEditInfo } from './steps/admin-config-wizard-edit-info.component'
|
||||||
import { AdminConfigWizardFormComponent } from './steps/admin-config-wizard-form.component'
|
import { AdminConfigWizardFormComponent } from './steps/admin-config-wizard-form.component'
|
||||||
import { AdminConfigWizardPreviewComponent } from './steps/admin-config-wizard-preview.component'
|
import { AdminConfigWizardPreviewComponent } from './steps/admin-config-wizard-preview.component'
|
||||||
import { AdminConfigWizardWelcomeComponent } from './steps/admin-config-wizard-welcome.component'
|
import { AdminConfigWizardWelcomeComponent } from './steps/admin-config-wizard-welcome.component'
|
||||||
|
@ -37,7 +37,7 @@ export class AdminConfigWizardModalComponent implements OnInit {
|
||||||
readonly created = output()
|
readonly created = output()
|
||||||
|
|
||||||
usageType: UsageType
|
usageType: UsageType
|
||||||
instanceInfo: FormInfo
|
instanceInfo: FormEditInfo
|
||||||
|
|
||||||
showWelcome: boolean
|
showWelcome: boolean
|
||||||
dryRun: boolean
|
dryRun: boolean
|
||||||
|
|
|
@ -33,6 +33,13 @@
|
||||||
<div *ngIf="formErrors.shortDescription" class="form-error" role="alert">{{ formErrors.shortDescription }}</div>
|
<div *ngIf="formErrors.shortDescription" class="form-error" role="alert">{{ formErrors.shortDescription }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="avatarfile">Platform icon</label>
|
||||||
|
<div class="form-group-description" i18n>Used in various places such as on the website, mobile application and social media</div>
|
||||||
|
|
||||||
|
<my-preview-upload class="avatar-preview" formControlName="avatar" inputName="avatar" displayDelete="true"></my-preview-upload>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label i18n for="primaryColor">Primary color</label>
|
<label i18n for="primaryColor">Primary color</label>
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,11 @@ form {
|
||||||
height: 190px;
|
height: 190px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-preview {
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $small-view) {
|
@media screen and (max-width: $small-view) {
|
||||||
.mascot {
|
.mascot {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -11,22 +11,26 @@ import {
|
||||||
FormReactiveMessagesTyped
|
FormReactiveMessagesTyped
|
||||||
} from '@app/shared/form-validators/form-validator.model'
|
} from '@app/shared/form-validators/form-validator.model'
|
||||||
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
|
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
|
||||||
|
import { PreviewUploadComponent } from '@app/shared/shared-forms/preview-upload.component'
|
||||||
import { ColorPickerModule } from 'primeng/colorpicker'
|
import { ColorPickerModule } from 'primeng/colorpicker'
|
||||||
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
|
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
|
||||||
|
import { findAppropriateImage } from '@peertube/peertube-core-utils'
|
||||||
|
import { logger } from '@root-helpers/logger'
|
||||||
|
|
||||||
type Form = {
|
type Form = {
|
||||||
platformName: FormControl<string>
|
platformName: FormControl<string>
|
||||||
shortDescription: FormControl<string>
|
shortDescription: FormControl<string>
|
||||||
|
avatar: FormControl<Blob>
|
||||||
primaryColor: FormControl<string>
|
primaryColor: FormControl<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormInfo = FormDefaultTyped<Form>
|
export type FormEditInfo = FormDefaultTyped<Form>
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-admin-config-wizard-edit-info',
|
selector: 'my-admin-config-wizard-edit-info',
|
||||||
templateUrl: './admin-config-wizard-edit-info.component.html',
|
templateUrl: './admin-config-wizard-edit-info.component.html',
|
||||||
styleUrls: [ './admin-config-wizard-edit-info.component.scss', '../shared/admin-config-wizard-modal-common.scss' ],
|
styleUrls: [ './admin-config-wizard-edit-info.component.scss', '../shared/admin-config-wizard-modal-common.scss' ],
|
||||||
imports: [ CommonModule, FormsModule, ReactiveFormsModule, ColorPickerModule, CdkStepperModule, ButtonComponent ]
|
imports: [ CommonModule, FormsModule, ReactiveFormsModule, ColorPickerModule, CdkStepperModule, ButtonComponent, PreviewUploadComponent ]
|
||||||
})
|
})
|
||||||
export class AdminConfigWizardEditInfoComponent implements OnInit {
|
export class AdminConfigWizardEditInfoComponent implements OnInit {
|
||||||
private server = inject(ServerService)
|
private server = inject(ServerService)
|
||||||
|
@ -38,7 +42,7 @@ export class AdminConfigWizardEditInfoComponent implements OnInit {
|
||||||
readonly showBack = input.required({ transform: booleanAttribute })
|
readonly showBack = input.required({ transform: booleanAttribute })
|
||||||
|
|
||||||
readonly back = output()
|
readonly back = output()
|
||||||
readonly next = output<FormInfo>()
|
readonly next = output<FormEditInfo>()
|
||||||
readonly hide = output()
|
readonly hide = output()
|
||||||
|
|
||||||
form: FormGroup<Form>
|
form: FormGroup<Form>
|
||||||
|
@ -47,12 +51,23 @@ export class AdminConfigWizardEditInfoComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.buildForm()
|
this.buildForm()
|
||||||
|
|
||||||
|
const avatar = findAppropriateImage(this.server.getHTMLConfig().instance.avatars, 128)
|
||||||
|
if (avatar) {
|
||||||
|
fetch(avatar.fileUrl)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => this.form.patchValue({ avatar: blob }))
|
||||||
|
.catch(() => {
|
||||||
|
logger.error('Could not fetch instance avatar')
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildForm () {
|
private buildForm () {
|
||||||
const obj: BuildFormArgumentTyped<Form> = {
|
const obj: BuildFormArgumentTyped<Form> = {
|
||||||
platformName: INSTANCE_NAME_VALIDATOR,
|
platformName: INSTANCE_NAME_VALIDATOR,
|
||||||
shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
|
shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
|
||||||
|
avatar: null,
|
||||||
primaryColor: null
|
primaryColor: null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +82,7 @@ export class AdminConfigWizardEditInfoComponent implements OnInit {
|
||||||
this.validationMessages = validationMessages
|
this.validationMessages = validationMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultValues (): FormDefaultTyped<Form> {
|
private getDefaultValues (): FormEditInfo {
|
||||||
const config = this.server.getHTMLConfig()
|
const config = this.server.getHTMLConfig()
|
||||||
const primaryColorConfig = config.theme.customization.primaryColor
|
const primaryColorConfig = config.theme.customization.primaryColor
|
||||||
|
|
||||||
|
@ -78,6 +93,7 @@ export class AdminConfigWizardEditInfoComponent implements OnInit {
|
||||||
return {
|
return {
|
||||||
platformName: config.instance.name,
|
platformName: config.instance.name,
|
||||||
shortDescription: config.instance.shortDescription,
|
shortDescription: config.instance.shortDescription,
|
||||||
|
avatar: undefined as Blob,
|
||||||
primaryColor
|
primaryColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,9 @@ import { ColorPickerModule } from 'primeng/colorpicker'
|
||||||
import { concatMap, from, switchMap, toArray } from 'rxjs'
|
import { concatMap, from, switchMap, toArray } from 'rxjs'
|
||||||
import { PartialDeep } from 'type-fest'
|
import { PartialDeep } from 'type-fest'
|
||||||
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
|
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
|
||||||
import { FormInfo } from './admin-config-wizard-edit-info.component'
|
import { FormEditInfo } from './admin-config-wizard-edit-info.component'
|
||||||
import { UsageType } from './usage-type/usage-type.model'
|
import { UsageType } from './usage-type/usage-type.model'
|
||||||
|
import { InstanceLogoService } from '@app/shared/shared-instance/instance-logo.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-admin-config-wizard-preview',
|
selector: 'my-admin-config-wizard-preview',
|
||||||
|
@ -26,7 +27,7 @@ import { UsageType } from './usage-type/usage-type.model'
|
||||||
CdkStepperModule,
|
CdkStepperModule,
|
||||||
ButtonComponent
|
ButtonComponent
|
||||||
],
|
],
|
||||||
providers: [ AdminConfigService, PluginApiService ]
|
providers: [ AdminConfigService, PluginApiService, InstanceLogoService ]
|
||||||
})
|
})
|
||||||
export class AdminConfigWizardPreviewComponent implements OnChanges {
|
export class AdminConfigWizardPreviewComponent implements OnChanges {
|
||||||
private adminConfig = inject(AdminConfigService)
|
private adminConfig = inject(AdminConfigService)
|
||||||
|
@ -34,11 +35,12 @@ export class AdminConfigWizardPreviewComponent implements OnChanges {
|
||||||
private notifier = inject(Notifier)
|
private notifier = inject(Notifier)
|
||||||
private html = inject(HtmlRendererService)
|
private html = inject(HtmlRendererService)
|
||||||
private server = inject(ServerService)
|
private server = inject(ServerService)
|
||||||
|
private instanceLogo = inject(InstanceLogoService)
|
||||||
|
|
||||||
readonly currentStep = input.required({ transform: numberAttribute })
|
readonly currentStep = input.required({ transform: numberAttribute })
|
||||||
readonly totalSteps = input.required({ transform: numberAttribute })
|
readonly totalSteps = input.required({ transform: numberAttribute })
|
||||||
readonly usageType = input.required<UsageType>()
|
readonly usageType = input.required<UsageType>()
|
||||||
readonly instanceInfo = input.required<FormInfo>()
|
readonly instanceInfo = input.required<FormEditInfo>()
|
||||||
readonly dryRun = input.required({ transform: booleanAttribute })
|
readonly dryRun = input.required({ transform: booleanAttribute })
|
||||||
|
|
||||||
readonly back = output()
|
readonly back = output()
|
||||||
|
@ -84,6 +86,12 @@ export class AdminConfigWizardPreviewComponent implements OnChanges {
|
||||||
this.updating = true
|
this.updating = true
|
||||||
|
|
||||||
this.adminConfig.updateCustomConfig(this.config)
|
this.adminConfig.updateCustomConfig(this.config)
|
||||||
|
.pipe(() => {
|
||||||
|
const avatar = this.instanceInfo().avatar
|
||||||
|
if (avatar) return this.instanceLogo.updateAvatar(avatar)
|
||||||
|
|
||||||
|
return this.instanceLogo.deleteAvatar()
|
||||||
|
})
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(() => this.server.resetConfig()),
|
switchMap(() => this.server.resetConfig()),
|
||||||
switchMap(() => {
|
switchMap(() => {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { AsyncValidatorFn, FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms'
|
import { AsyncValidatorFn, FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms'
|
||||||
import { PartialDeep } from 'type-fest'
|
|
||||||
|
|
||||||
export type BuildFormValidator = {
|
export type BuildFormValidator = {
|
||||||
VALIDATORS: ValidatorFn[]
|
VALIDATORS: ValidatorFn[]
|
||||||
|
@ -19,7 +18,7 @@ export type BuildFormArgumentTyped<Form> = ReplaceForm<Form, BuildFormValidator>
|
||||||
export type FormDefault = {
|
export type FormDefault = {
|
||||||
[name: string]: Blob | Date | boolean | number | number[] | string | string[] | FormDefault
|
[name: string]: Blob | Date | boolean | number | number[] | string | string[] | FormDefault
|
||||||
}
|
}
|
||||||
export type FormDefaultTyped<Form> = PartialDeep<UnwrapForm<Form>>
|
export type FormDefaultTyped<Form> = Partial<UnwrapForm<Form>>
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -42,8 +41,9 @@ export type UnwrapForm<Form> = {
|
||||||
[K in keyof Form]: _UnwrapForm<Form[K]>
|
[K in keyof Form]: _UnwrapForm<Form[K]>
|
||||||
}
|
}
|
||||||
|
|
||||||
type _UnwrapForm<T> = T extends FormGroup<infer U> ? UnwrapForm<U> :
|
type _UnwrapForm<T> = T extends FormGroup<infer U> ? Partial<UnwrapForm<U>> :
|
||||||
T extends FormArray<infer U> ? _UnwrapForm<U>[] :
|
T extends FormArray<infer U> ? _UnwrapForm<U>[] :
|
||||||
|
T extends FormControl<Blob> ? Blob :
|
||||||
T extends FormControl<infer U> ? U
|
T extends FormControl<infer U> ? U
|
||||||
: never
|
: never
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
export function findAppropriateImage<T extends { width: number, height: number }> (images: T[], wantedWidth: number) {
|
export function findAppropriateImage<T extends { width: number, height: number }> (images: T[], wantedWidth: number) {
|
||||||
|
if (!images || images.length === 0) return undefined
|
||||||
|
|
||||||
const imagesSorted = images.sort((a, b) => a.width - b.width)
|
const imagesSorted = images.sort((a, b) => a.width - b.width)
|
||||||
|
|
||||||
for (const image of imagesSorted) {
|
for (const image of imagesSorted) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue