Skip to content

Commit

Permalink
Animations update
Browse files Browse the repository at this point in the history
  • Loading branch information
logashoff committed May 14, 2024
1 parent fea82ce commit 1d91c8a
Show file tree
Hide file tree
Showing 22 changed files with 211 additions and 131 deletions.
2 changes: 1 addition & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"minify": true,
"inlineCritical": false
},
"fonts": false
"fonts": true
},
"outputHashing": "all",
"sourceMap": false,
Expand Down
4 changes: 2 additions & 2 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApplicationConfig, importProvidersFrom } from '@angular/core';

import { HttpClient, provideHttpClient } from '@angular/common/http';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { PreloadAllModules, provideRouter, withHashLocation, withPreloading } from '@angular/router';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
Expand All @@ -10,7 +10,7 @@ import { appRoutes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideAnimations(),
provideAnimationsAsync(),
provideRouter(appRoutes, withPreloading(PreloadAllModules), withHashLocation()),
importProvidersFrom([
TranslateModule.forRoot({
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Routes } from '@angular/router';
import { HomeService } from './services/index';

export const appRoutes: Routes = [
{
path: 'new-tab',
providers: [HomeService],
loadComponent: () => import('./components/new-tab/new-tab.component').then((m) => m.NewTabComponent),
loadChildren: () => import('./components/new-tab/new-tab.routes').then((m) => m.newTabRoutes),
},
Expand Down
6 changes: 6 additions & 0 deletions src/app/components/groups/groups.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@
<app-list-item
cdkDrag
[cdkDragDisabled]="dragDisabled"
[animated]="animatedTabs.has(tab)"
[tab]="tab"
[tabs]="timelineTabs$ | async"
[openTabs]="openTabs$ | async"
[target]="isPopup ? '_blank' : '_self'"
(modified)="editTab(tab)"
(deleted)="deleteTab(tab)"
[focused]="(activeGroupId$ | async) === group.id && (activeTabId$ | async) === tab.id" />
}
</app-tab-list>
Expand Down
25 changes: 24 additions & 1 deletion src/app/components/groups/groups.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { BehaviorSubject, Observable, map, shareReplay } from 'rxjs';
import { IsReadOnlyGroupPipe } from '../../pipes/index';
import { NavService, SettingsService, TabService } from '../../services/index';
import { BrowserTabs, GroupExpanded, TabGroup, TabGroups, TabsByHostname } from '../../utils/index';
import { BrowserTab, BrowserTabs, GroupExpanded, TabGroup, TabGroups, TabsByHostname } from '../../utils/index';
import { GroupControlsComponent } from '../group-controls/group-controls.component';
import { ListItemComponent } from '../list-item/list-item.component';
import { PanelHeaderComponent } from '../panel-header/panel-header.component';
Expand Down Expand Up @@ -90,8 +90,18 @@ export class GroupsComponent {
*/
readonly panelStates$: Observable<GroupExpanded>;

/**
* When tabs are deleted and restored or when tabs are modified,
* highlight changes by playing animation
*/
readonly animatedTabs = new Set<BrowserTab>();

readonly isNaN = isNaN;

readonly openTabs$ = this.tabService.openTabChanges$.pipe(shareReplay(1));
readonly timelineTabs$ = this.tabService.tabs$.pipe(shareReplay(1));
readonly isPopup = this.navService.isPopup;

constructor(
private readonly navService: NavService,
private readonly tabService: TabService,
Expand Down Expand Up @@ -127,4 +137,17 @@ export class GroupsComponent {
moveItemInArray(tabs, event.previousIndex, event.currentIndex);
this.tabService.save();
}

async editTab(tab: BrowserTab) {
const updatedTab = await this.tabService.updateTab(tab);

if (updatedTab) {
this.animatedTabs.add(updatedTab);
}
}

async deleteTab(tab: BrowserTab) {
await this.tabService.removeTab(tab);
this.animatedTabs.add(tab);
}
}
4 changes: 2 additions & 2 deletions src/app/components/list-item/list-item.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<div class="subtitle-container">
@if (hasLabels$ | async) {
<span class="label-container">
@if (openTabs$ | async) {
@if (openTabsCount$ | async) {
<app-label color="primary">
{{ 'openTabs' | translate: { count: openTabs$ | async } }}
{{ 'openTabs' | translate: { count: openTabsCount$ | async } }}
</app-label>
}

Expand Down
123 changes: 67 additions & 56 deletions src/app/components/list-item/list-item.component.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
HostBinding,
Input,
OnInit,
Output,
ViewEncapsulation,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { EXPANSION_PANEL_ANIMATION_TIMING } from '@angular/material/expansion';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { BehaviorSubject, Observable, combineLatest, map, shareReplay, switchMap } from 'rxjs';
import { BehaviorSubject, Observable, combineLatest, filter, map, shareReplay, switchMap } from 'rxjs';
import { StopPropagationDirective } from '../../directives/index';
import { FaviconPipe } from '../../pipes/index';
import { NavService, TabService } from '../../services/index';
import { BrowserTab, BrowserTabs, TabDelete, Tabs } from '../../utils/index';
import { BrowserTab, BrowserTabs, Tabs, listItemAnimation } from '../../utils/index';
import { ChipComponent } from '../chip/chip.component';
import { LabelComponent } from '../label/label.component';
import { RippleComponent } from '../ripple/ripple.component';
Expand Down Expand Up @@ -47,34 +45,43 @@ import { RippleComponent } from '../ripple/ripple.component';
StopPropagationDirective,
TranslateModule,
],
animations: [
trigger('fadeAnimation', [
state(
'void',
style({
transform: 'translateY(20%)',
opacity: 0,
})
),
transition('void => *', animate(EXPANSION_PANEL_ANIMATION_TIMING)),
]),
],
animations: [listItemAnimation],
})
export class ListItemComponent {
private readonly tab$ = new BehaviorSubject<BrowserTab>(null);
export class ListItemComponent implements OnInit {
readonly #tab$ = new BehaviorSubject<BrowserTab>(null);

@HostBinding('@.disabled')
private animationDisabled = true;

@HostBinding('@listItemAnimation')
@Input()
set animated(value: boolean) {
this.animationDisabled = !value;
}

get animated(): boolean {
return !this.animationDisabled;
}

@HostBinding('@fadeAnimation')
@Input()
set tab(value: BrowserTab) {
this.tab$.next(value);
this.#tab$.next(value);
}

get tab(): BrowserTab {
return this.tab$.value;
return this.#tab$.value;
}

readonly #tabs$ = new BehaviorSubject<BrowserTabs>(null);

@Input() set tabs(value: BrowserTabs) {
this.#tabs$.next(value);
}

get savedTabs$(): Observable<BrowserTabs> {
return this.tabService?.tabs$.pipe(shareReplay(1));
readonly #openTabs$ = new BehaviorSubject<Tabs>(null);

@Input() set openTabs(value: Tabs) {
this.#openTabs$.next(value);
}

/**
Expand All @@ -85,16 +92,26 @@ export class ListItemComponent {
/**
* Disables item menu
*/
readonly notReadOnly$: Observable<boolean> = this.tab$.pipe(
switchMap((tab) => this.savedTabs$.pipe(map((tabs) => tabs.some((t) => t.id === tab.id)))),
readonly notReadOnly$: Observable<boolean> = this.#tab$.pipe(
switchMap((tab) =>
this.#tabs$.pipe(
filter((tabs) => tabs?.length > 0),
map((tabs) => tabs.some((t) => t.id === tab.id))
)
),
shareReplay(1)
);

/**
* Indicates if list item is part of timeline.
*/
readonly inTimeline$: Observable<boolean> = this.tab$.pipe(
switchMap((tab) => this.savedTabs$.pipe(map((tabs) => tabs.some((t) => t.id === tab.id)))),
readonly inTimeline$: Observable<boolean> = this.#tab$.pipe(
switchMap((tab) =>
this.#tabs$.pipe(
filter((tabs) => tabs?.length > 0),
map((tabs) => tabs.some((t) => t.id === tab.id))
)
),
shareReplay(1)
);

Expand All @@ -106,38 +123,39 @@ export class ListItemComponent {
/**
* Dispatches event when Delete menu item is clicked
*/
@Output() readonly deleted = new EventEmitter<TabDelete>();
@Output() readonly deleted = new EventEmitter<BrowserTab>();

/**
* Scroll this list item into view
*/
@Output() readonly find = new EventEmitter<BrowserTab>();

/**
* Target where URL will be opened when list item is clicked
* Target window to open URL
*/
get target(): string {
return this.nav.isPopup ? '_blank' : '_self';
}
@Input() target: '_blank' | '_self' = '_self';

/**
* Indicates how many tabs are currently open that match this tab's URL
*/
readonly openTabs$: Observable<number>;

readonly dupTabs$: Observable<number> = this.tab$.pipe(
switchMap((tab) => this.savedTabs$.pipe(map((tabs) => tabs.filter((t) => t.url === tab.url)?.length)))
openTabsCount$: Observable<number>;

readonly dupTabs$: Observable<number> = this.#tab$.pipe(
switchMap((tab) =>
this.#tabs$.pipe(
filter((tabs) => tabs?.length > 0),
map((tabs) => tabs.filter((t) => t.url === tab.url)?.length)
)
),
shareReplay(1)
);

readonly activeTab$: Observable<boolean>;
readonly pinnedTab$: Observable<boolean>;
readonly hasLabels$: Observable<boolean>;
activeTab$: Observable<boolean>;
pinnedTab$: Observable<boolean>;
hasLabels$: Observable<boolean>;

constructor(
private tabService: TabService,
private nav: NavService
) {
const openTabs$: Observable<Tabs> = combineLatest([this.tab$, this.tabService.tabChanges$]).pipe(
ngOnInit() {
const openTabs$: Observable<Tabs> = combineLatest([this.#tab$, this.#openTabs$]).pipe(
map(([tab, tabs]) => tabs?.filter((t) => t.url === tab.url)),
shareReplay(1)
);
Expand All @@ -152,12 +170,12 @@ export class ListItemComponent {
shareReplay(1)
);

this.openTabs$ = openTabs$.pipe(
this.openTabsCount$ = openTabs$.pipe(
map((tabs) => tabs?.length),
shareReplay(1)
);

this.hasLabels$ = combineLatest([this.activeTab$, this.pinnedTab$, this.openTabs$, this.dupTabs$]).pipe(
this.hasLabels$ = combineLatest([this.activeTab$, this.pinnedTab$, this.openTabsCount$, this.dupTabs$]).pipe(
map(([active, pinned, openTabs, dupTabs]) => active || pinned || openTabs > 0 || dupTabs > 1),
shareReplay(1)
);
Expand All @@ -167,20 +185,13 @@ export class ListItemComponent {
* Opens dialog to edit specified tab.
*/
async editClick() {
const updatedTab = await this.tabService.updateTab(this.tab);

this.modified.emit(updatedTab);
this.modified.emit(this.tab);
}

/**
* Handles delete menu item click
*/
async deleteClick() {
const messageRef = await this.tabService.removeTab(this.tab);

this.deleted.emit({
deletedTab: this.tab,
revertDelete: messageRef,
});
this.deleted.emit(this.tab);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { TimelineElementComponent } from '../timeline-element/timeline-element.c
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, EmptyComponent, GroupsComponent, TimelineElementComponent],
providers: [HomeService],
})
export class NewTabContentComponent {
readonly defaultActions: CollectionActions = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { SearchComponent } from '../search/search.component';
selector: 'app-new-tab-search',
standalone: true,
imports: [CommonModule, SearchComponent],
providers: [HomeService],
templateUrl: './new-tab-search.component.html',
styleUrl: './new-tab-search.component.scss',
})
Expand Down
7 changes: 3 additions & 4 deletions src/app/components/new-tab/new-tab.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
@if (topSites$ | async) {
<app-top-sites
@if (topSites$ | async; as topSites) {
<app-top-sites [@hideAnimation]="(hideTopSites$ | async) ? 'hide' : null"
class="top-sites"
[ngClass]="{ hidden: hideTopSites$ | async }"
[topSites]="topSites$ | async" />
[topSites]="topSites" />
}
<app-search-form
class="search-form"
Expand Down
13 changes: 6 additions & 7 deletions src/app/components/new-tab/new-tab.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ app-new-tab {

.top-sites {
overflow: hidden;

&.hidden {
visibility: hidden;
height: 0;
}
}

.content,
Expand All @@ -39,8 +34,12 @@ app-new-tab {
max-width: 75rem;
}

.search-form.search-margin {
margin-top: 2rem;
.search-form {
transition: margin $cubic-ease;

&.search-margin {
margin-top: 2rem;
}
}
}

Expand Down
Loading

0 comments on commit 1d91c8a

Please sign in to comment.