feat(tour): add basic steps

This commit is contained in:
Johannes Millan 2024-01-24 14:54:22 +01:00
parent 64ba20a227
commit 74d1c40964
14 changed files with 882 additions and 206 deletions

View file

@ -35,7 +35,10 @@
"src/manifest.json",
"src/static"
],
"styles": ["src/styles.scss"],
"styles": [
"src/styles.scss",
"node_modules/shepherd.js/dist/css/shepherd.css"
],
"scripts": [],
"webWorkerTsConfig": "src/tsconfig.worker.json"
},
@ -210,7 +213,10 @@
"tsConfig": "src/tsconfig.spec.json",
"preserveSymlinks": true,
"karmaConfig": "src/karma.conf.js",
"styles": ["src/styles.scss"],
"styles": [
"src/styles.scss",
"node_modules/shepherd.js/dist/css/shepherd.css"
],
"scripts": [],
"assets": ["src/favicon.ico", "src/assets", "src/manifest.json"]
}

710
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -107,12 +107,14 @@
],
"dependencies": {
"@electron/remote": "^2.0.12",
"angular-shepherd": "^14.0.0",
"electron-dl": "^3.5.1",
"electron-localshortcut": "^3.2.1",
"electron-log": "^5.0.1",
"electron-window-state": "^5.0.3",
"fs-extra": "^11.1.1",
"node-fetch": "^2.7.0"
"node-fetch": "^2.7.0",
"shepherd.js": "^11.2.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^14.1.1",

View file

@ -110,3 +110,5 @@
</svg>
</div>
</div>
<shepherd></shepherd>

View file

@ -51,13 +51,14 @@ import { WelcomeModule } from './features/welcome/welcome.module';
import { DominaModeModule } from './features/domina-mode/domina-mode.module';
import { FocusModeModule } from './features/focus-mode/focus-mode.module';
import { CalendarIntegrationModule } from './features/calendar-integration/calendar-integration.module';
import { ShepherdComponent } from './features/shepherd/shepherd.component';
// NOTE: export required for aot to work
export const createTranslateLoader = (http: HttpClient): TranslateHttpLoader =>
new TranslateHttpLoader(http, './assets/i18n/', '.json');
@NgModule({
declarations: [AppComponent],
declarations: [AppComponent, ShepherdComponent],
imports: [
// Those features need to be included first for store not to mess up, probably because we use it initially at many places
ConfigModule,

View file

@ -0,0 +1,52 @@
import { Observable, Subject } from 'rxjs';
import Shepherd from 'shepherd.js';
import Step = Shepherd.Step;
import { first, takeUntil, tap } from 'rxjs/operators';
export const waitForEl = (selector: string, cb: () => void): void => {
const int = window.setInterval(() => {
if (document.querySelector(selector)) {
window.clearInterval(int);
cb();
}
}, 50);
};
export const waitForElRemove = (
el: HTMLElement | Element | null,
cb: () => void,
): void => {
if (!el) {
throw new Error('No el provided');
}
const int = window.setInterval(() => {
if (!document.contains(el)) {
window.clearInterval(int);
cb();
}
}, 50);
};
export const waitForObs = (
obs: Observable<any>,
cb: () => void,
): Partial<Step.StepOptions> => {
let _onDestroy$;
return {
when: {
show: () => {
_onDestroy$ = new Subject<void>();
obs
.pipe(
takeUntil(_onDestroy$),
tap((v) => console.log('waitForObs', v)),
first(),
)
.subscribe(() => cb());
},
hide: () => {
_onDestroy$.next();
_onDestroy$.complete();
},
},
};
};

View file

@ -0,0 +1,207 @@
import Step from 'shepherd.js/src/types/step';
import { ShepherdService } from 'angular-shepherd';
import { waitForEl, waitForObs } from './shepherd-helper';
import { LayoutService } from '../../core-ui/layout/layout.service';
import { TaskService } from '../tasks/task.service';
import { distinctUntilChanged, filter, skip, tap } from 'rxjs/operators';
import { promiseTimeout } from '../../util/promise-timeout';
const NEXT_BTN = {
classes: 'shepherd-button-primary',
text: 'Next',
type: 'next',
};
export const SHEPHERD_STANDARD_BTNS = [
{
classes: 'shepherd-button-secondary',
text: 'Exit',
type: 'cancel',
},
{
classes: 'shepherd-button-primary',
text: 'Back',
type: 'back',
},
NEXT_BTN,
];
export const SHEPHERD_STEPS = (
shepherdService: ShepherdService,
layoutService: LayoutService,
taskService: TaskService,
): Array<Step.StepOptions> => [
// TODO remove
{
title: 'YXXXXO',
// beforeShowPromise: () => promiseTimeout(200),
when: {
show: () => {
setTimeout(() => {
shepherdService.next();
}, 500);
},
},
buttons: [],
},
// {
// title: 'Welcome to Super Productivity!!',
// text: 'Super Productivity is a ToDo app that helps you to improve your personal workflows.',
// buttons: SHEPHERD_STANDARD_BTNS,
// },
// {
// attachTo: {
// element: '.action-nav button',
// on: 'bottom',
// },
// when: {
// show: () => {
// waitForEl('app-root > add-task-bar input', () => shepherdService.next());
// },
// },
// scrollTo: false,
// title: "Let's add your first task!",
// text: 'Click on this button or press <kbd>Shift</kbd> + <kbd>a</kbd>',
// advanceOn: {
// selector: '.action-nav button',
// event: 'click',
// },
// },
//
// {
// attachTo: {
// element: 'add-task-bar',
// on: 'bottom',
// },
// beforeShowPromise: () => promiseTimeout(1000),
// when: {
// show: () => {
// waitForEl('task', () => {
// layoutService.hideAddTaskBar();
// shepherdService.next();
// });
// },
// },
// scrollTo: false,
// title: 'Enter a title!',
// text: 'Enter the title you want to give your task and hit the <kbd>Enter</kbd> key. After that you can press the <kbd>Escape</kbd> key or click anywhere on the grayed out backdrop to leave the add task bar.',
// },
// {
// title: 'Congrats! This is your first task!',
// text: 'Hover over it with your mouse',
// attachTo: {
// element: 'task',
// on: 'bottom',
// },
// beforeShowPromise: () => promiseTimeout(1000),
// when: {
// show: () => {
// setTimeout(() => {
// waitForEl('task .hover-controls', () => shepherdService.next());
// }, 1000);
// },
// },
// },
// {
// title: 'Start Tracking',
// attachTo: {
// element: '.start-task-btn',
// on: 'bottom',
// },
// text: 'Pressing the play button will start your first time tracking session. Time tracking is useful since it allows you to get a better idea on how you spend your time.',
// // attachTo: {
// // element: 'add-task-bar',
// // on: 'bottom',
// // },
//
// ...waitForObs(taskService.currentTaskId$.pipe(filter((id) => !!id)), () =>
// shepherdService.next(),
// ),
//
// },
// {
// title: 'Stop Tracking',
// text: 'To stop tracking click on the pause button.',
// attachTo: {
// element: '.start-task-btn',
// on: 'bottom',
// },
// ...waitForObs(taskService.currentTaskId$.pipe(filter((id) => !id)), () =>
// shepherdService.next(),
// ),
// },
// {
// title: 'Edit Task Title',
// text: 'You can edit the task title by clicking on it. Do this now and change the title to something else!',
// attachTo: {
// element: '.task-title',
// on: 'bottom',
// },
// advanceOn: {
// selector: '.task-title',
// event: 'blur',
// },
// },
// {
// title: 'Task Side Panel',
// text: 'There is more you you can do with task. Hover over the task you created with your mouse again.',
// buttons: [],
// attachTo: {
// element: 'task',
// on: 'bottom',
// },
// beforeShowPromise: () => promiseTimeout(500),
// when: {
// show: () => {
// setTimeout(() => {
// waitForEl('task .hover-controls', () => shepherdService.next());
// }, 200);
// },
// },
// },
// {
// title: 'Opening Task Side Panel',
// attachTo: {
// element: '.show-additional-info-btn',
// on: 'bottom',
// },
// text: 'You can open a panel with additional controls by clicking on the button. Alternatively you can press the <kbd>➔</kbd> key when a task is focused.',
// buttons: [],
// ...waitForObs(
// taskService.selectedTask$.pipe(filter((selectedTask) => !!selectedTask)),
// () => shepherdService.next(),
// ),
// },
// {
// title: 'The Task Side Panel',
// text: 'In the task side panel you can adjust estimates, schedule your task, add a description or attachments or configure your task to be repeated.',
// buttons: [NEXT_BTN],
// },
// {
// title: 'Closing the Task Side Panel',
// text: 'You can close the panel by clicking the X or by pressing <kbd>←</kbd>. Do this now!',
// attachTo: {
// element: '.show-additional-info-btn',
// on: 'bottom',
// },
// ...waitForObs(
// taskService.selectedTask$.pipe(filter((selectedTask) => !selectedTask)),
// () => shepherdService.next(),
// ),
// },
{
title: 'Deleting a Task',
text: 'To delete a task you need to open the task context menu.',
when: {
show: () => {
waitForEl('mat-menu-panel', () => shepherdService.next());
},
},
},
{
title: 'These are the basics',
text: 'Best',
buttons: [],
},
];

View file

@ -0,0 +1,23 @@
// import { ComponentFixture, TestBed } from '@angular/core/testing';
//
// import { ShepherdComponent } from './shepherd.component';
//
// describe('ShepherdComponent', () => {
// let component: ShepherdComponent;
// let fixture: ComponentFixture<ShepherdComponent>;
//
// beforeEach(async () => {
// await TestBed.configureTestingModule({
// declarations: [ ShepherdComponent ]
// })
// .compileComponents();
//
// fixture = TestBed.createComponent(ShepherdComponent);
// component = fixture.componentInstance;
// fixture.detectChanges();
// });
//
// it('should create', () => {
// expect(component).toBeTruthy();
// });
// });

View file

@ -0,0 +1,38 @@
import { AfterViewInit, ChangeDetectionStrategy, Component } from '@angular/core';
import { ShepherdService } from 'angular-shepherd';
import { SHEPHERD_STANDARD_BTNS, SHEPHERD_STEPS } from './shepherd-steps.const';
import { LayoutService } from '../../core-ui/layout/layout.service';
import { TaskService } from '../tasks/task.service';
@Component({
selector: 'shepherd',
template: '',
// templateUrl: './shepherd.component.html',
// styleUrls: ['./shepherd.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShepherdComponent implements AfterViewInit {
constructor(
private shepherdService: ShepherdService,
private layoutService: LayoutService,
private taskService: TaskService,
) {}
ngAfterViewInit(): void {
this.shepherdService.defaultStepOptions = {
scrollTo: false,
highlightClass: 'shepherd-highlight',
arrow: true,
cancelIcon: {
enabled: true,
},
buttons: [],
};
// this.shepherdService.modal = true;
// this.shepherdService.confirmCancel = false;
this.shepherdService.addSteps(
SHEPHERD_STEPS(this.shepherdService, this.layoutService, this.taskService) as any,
);
this.shepherdService.start();
}
}

View file

@ -245,7 +245,8 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
const { className } = relatedTarget;
isUIelement =
className.includes('switch-add-to-btn') ||
className.includes('switch-add-to-bot-btn');
className.includes('switch-add-to-bot-btn') ||
className.includes('shepherd-enabled');
}
if (

View file

@ -13,3 +13,4 @@
@import 'promise-btn';
@import 'global-error-alert';
@import 'wrap-buttons';
@import 'shepherd';

View file

@ -0,0 +1,35 @@
.shepherd-modal-overlay-container {
width: 100%;
height: 100% !important;
//opacity: .2 !important;
}
.shepherd-highlight {
outline: 3px solid $c-accent !important;
}
.shepherd-text kbd {
background-color: #eee;
border-radius: 3px;
border: 1px solid #b4b4b4;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 2px 0 0 rgba(255, 255, 255, 0.7) inset;
color: #333;
display: inline-block;
font-size: 0.85em;
font-weight: 700;
line-height: 1;
padding: 2px 4px;
white-space: nowrap;
}
.shepherd-header {
h3 {
margin: 0;
font-weight: bold;
}
}
.shepherd-element[data-popper-reference-hidden]:not(.shepherd-centered) {
opacity: 1 !important;
visibility: visible !important;
}