Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: saving state of features upon reload #27

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,52 @@ $ yarn cypress open
```

Choose E2E Testing, and select a browser to start running the Specs

## Feature Development

### State Saving

Astral supports state saving, meaning keys are saved to localStorage to save the user's configuration of the tool. When developing new features to add in state saving you can follow a similar setup to existing widgets.

1. Import the Parent class for all features:

```js
import { AccessibilityComponent } from "./accessibility.component";
```

2. Inhert Parent class properties, call `super()` in new constructor, and set the current state:
Note: We prefix the key to be set with `astralAccessibility_` to not clash with user's localStorage

```js
export class <newComponent> extends AccessibilityComponent {
constructor() {
super();
this.currentState = super.setLogic("astralAccessibility_<newFeatureState>");
...
}
}
```

3. Initialize current state to get from the localStorage:

```js
currentState = super.getState("astralAccessibility_<newFeatureState>");
```

4. In the `nextState()` function use the Parent `changeState(currentState, localStorageKey, numOfStates)` function:

```js
this.currentState = super.changeState(
this.currentState,
"astralAccessibility_<newFeatureState>",
this.states.length,
);
```

5. The Child class function `_runStateLogic()` function should override the Parent class

```js
protected override _runStateLogic(){
...
}
```
1 change: 1 addition & 0 deletions cypress/e2e/astral-accessibility.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ describe("template spec", () => {
cy.document().find(".mask-top").should("not.exist");
screenMaskComponent.click();
cy.document().find(".mask-top").should("exist");
cy.clearAllLocalStorage();
cy.reload();
cy.document().find(".mask-top").should("not.exist");
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"ng-packagr": "^14.1.0",
"ngx-build-plus": "14",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.2",
"prettier": "^3.0.3",
"primeicons": "^6.0.1",
"typescript": "~4.7.2"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Component } from "@angular/core";

@Component({
standalone: true,
template: ``,
imports: [],
})
export abstract class AccessibilityComponent {
constructor() {}

changeState(currentState: number, state: string, numOfStates: number) {
currentState += 1;
currentState = currentState % numOfStates;
this.saveState(state, JSON.stringify(currentState));
return currentState;
}

saveState(key: string, value: string) {
localStorage.setItem(key, value);
}

getState(key: string) {
const textSizeState = localStorage.getItem(key);
return Number(textSizeState);
}

setLogic(state: string) {
const currentState = this.getState(state);
if (currentState == null) {
return 0;
} else {
this._runStateLogic();
return currentState;
}
}

protected _runStateLogic() {
//to be overridden
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DOCUMENT, NgIf, NgClass } from "@angular/common";
import { Component, inject } from "@angular/core";
import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
import { AccessibilityComponent } from "./accessibility.component";

@Component({
selector: "astral-contrast",
Expand Down Expand Up @@ -82,23 +83,30 @@ import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
`,
imports: [NgIf, NgClass, AstralCheckmarkSvgComponent],
})
export class ContrastComponent {
export class ContrastComponent extends AccessibilityComponent {
constructor() {
super();
this.currentState = super.setLogic("astralAccessibility_contrastState");
}
document = inject(DOCUMENT);

currentState = 0;
currentState = super.getState("astralAccessibility_contrastState");
base = "Contrast";
states = [this.base, "Invert", "High Contrast", "Dark High Contrast"];

_style: HTMLStyleElement;

nextState() {
this.currentState += 1;
this.currentState = this.currentState % 4;
this.currentState = super.changeState(
this.currentState,
"astralAccessibility_contrastState",
this.states.length,
Comment on lines +101 to +103
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like first and last argument can be defined only in accessibility.component.ts, and we can make the second argument be defined as a class variable and have the parent read it as well. Hope that makes sense.

Read more on Template Method Design Pattern: https://refactoring.guru/design-patterns/template-method

);

this._runStateLogic();
}

private _runStateLogic() {
protected override _runStateLogic() {
this._style?.remove?.();
this._style = this.document.createElement("style");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DOCUMENT, NgIf, NgClass } from "@angular/common";
import { Component, Renderer2, inject } from "@angular/core";
import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
import { AccessibilityComponent } from "./accessibility.component";

@Component({
selector: "astral-line-height",
Expand Down Expand Up @@ -68,11 +69,14 @@ import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
`,
imports: [NgIf, NgClass, AstralCheckmarkSvgComponent],
})
export class LineHeightComponent {
constructor(private renderer: Renderer2) {}
export class LineHeightComponent extends AccessibilityComponent {
constructor(private renderer: Renderer2) {
super();
this.currentState = super.setLogic("astralAccessibility_lineHeightState");
}
document = inject(DOCUMENT);

currentState = 0;
currentState = super.getState("astralAccessibility_lineHeightState");
base = "Line Height";
states = [this.base, "Light Height", "Moderate Height", "Heavy Height"];

Expand All @@ -98,13 +102,16 @@ export class LineHeightComponent {
_style: HTMLStyleElement;

nextState() {
this.currentState += 1;
this.currentState = this.currentState % 4;
this.currentState = super.changeState(
this.currentState,
"astralAccessibility_lineHeightState",
this.states.length,
);

this._runStateLogic();
}

private _runStateLogic() {
protected override _runStateLogic() {
this._style?.remove?.();
this._style = this.document.createElement("style");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DOCUMENT, NgIf, NgClass } from "@angular/common";
import { Component, inject } from "@angular/core";
import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
import { AccessibilityComponent } from "./accessibility.component";

@Component({
selector: "astral-saturate",
Expand Down Expand Up @@ -86,21 +87,28 @@ import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
`,
imports: [NgIf, NgClass, AstralCheckmarkSvgComponent],
})
export class SaturateComponent {
export class SaturateComponent extends AccessibilityComponent {
constructor() {
super();
this.currentState = super.setLogic("astralAccessibility_saturateState");
}
document = inject(DOCUMENT);

currentState = 0;
currentState = super.getState("astralAccessibility_saturateState");
base = "Saturation";
states = [this.base, "Low Saturation", "High Saturation", "Desaturated"];

nextState() {
this.currentState += 1;
this.currentState = this.currentState % 4;
this.currentState = super.changeState(
this.currentState,
"astralAccessibility_saturateState",
this.states.length,
);

this._runStateLogic();
}

private _runStateLogic() {
protected override _runStateLogic() {
this._resetSaturation();

if (this.states[this.currentState] === "Low Saturation") {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DOCUMENT, NgIf, NgClass } from "@angular/common";
import { Component, Renderer2, inject } from "@angular/core";
import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
import { AccessibilityComponent } from "./accessibility.component";

@Component({
selector: "astral-screen-mask",
Expand Down Expand Up @@ -69,8 +70,11 @@ import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
`,
imports: [NgIf, NgClass, AstralCheckmarkSvgComponent],
})
export class ScreenMaskComponent {
constructor(private renderer: Renderer2) {}
export class ScreenMaskComponent extends AccessibilityComponent {
constructor(private renderer: Renderer2) {
super();
this.currentState = super.setLogic("astralAccessibility_screenMaskState");
}

cursorY = 0;
screenHeight: number = window.innerHeight;
Expand Down Expand Up @@ -167,20 +171,23 @@ export class ScreenMaskComponent {

document = inject(DOCUMENT);

currentState = 0;
currentState = super.getState("astralAccessibility_screenMaskState");
base = "Screen Mask";
states = [this.base, "Large Cursor", "Reading Mask"];

_style: HTMLStyleElement;

nextState() {
this.currentState += 1;
this.currentState = this.currentState % 3;
this.currentState = super.changeState(
this.currentState,
"astralAccessibility_screenMaskState",
this.states.length,
);

this._runStateLogic();
}

private _runStateLogic() {
protected override _runStateLogic() {
this._style?.remove?.();
this._style = this.document.createElement("style");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DOCUMENT, NgIf, NgClass } from "@angular/common";
import { Component, inject, Renderer2 } from "@angular/core";
import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
import { AccessibilityComponent } from "./accessibility.component";

@Component({
selector: "astral-screen-reader",
Expand Down Expand Up @@ -86,14 +87,17 @@ import { AstralCheckmarkSvgComponent } from "../util/astral-checksvg.component";
`,
imports: [NgIf, NgClass, AstralCheckmarkSvgComponent],
})
export class ScreenReaderComponent {
export class ScreenReaderComponent extends AccessibilityComponent {
globalListenFunction: Function;
speech = new SpeechSynthesisUtterance();
userAgent = navigator.userAgent;
isApple = false;
synthesisAvailable = true;

constructor(private renderer: Renderer2) {}
constructor(private renderer: Renderer2) {
super();
this.currentState = super.setLogic("astralAccessibility_screenReaderState");
}

readText(x: number, y: number) {
let element = document.elementFromPoint(x, y);
Expand Down Expand Up @@ -202,21 +206,24 @@ export class ScreenReaderComponent {

document = inject(DOCUMENT);

currentState = 0;
currentState = super.getState("astralAccessibility_screenReaderState");
base = "Screen Reader";
unavailableMessage = "Screen Reader unavailable on device";
states = [this.base, "Read Normal", "Read Fast", "Read Slow"];

_style: HTMLStyleElement;

nextState() {
this.currentState += 1;
this.currentState = this.currentState % 4;
this.currentState = super.changeState(
this.currentState,
"astralAccessibility_screenReaderState",
this.states.length,
);

this._runStateLogic();
}

private _runStateLogic() {
protected override _runStateLogic() {
this._style?.remove?.();
this._style = this.document.createElement("style");

Expand Down
Loading