@pb33f/cowboy-components 0.7.6 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ export declare class LoginButton extends LitElement {
7
7
  title: string;
8
8
  buttonLabel: string;
9
9
  redirectUrl: string;
10
+ textLink: boolean;
10
11
  oauthLogin: OAuthLogin;
11
12
  private controller;
12
13
  constructor();
@@ -12,6 +12,7 @@ import modalCss from "../../css/modal.css";
12
12
  import loginButtonCss from "./login-button.css";
13
13
  import tooltipCss from "../../css/tooltip.css";
14
14
  import { LogoutRequested } from "../../events/doctor";
15
+ import linksCss from "../../css/links.css";
15
16
  let LoginButton = class LoginButton extends LitElement {
16
17
  constructor() {
17
18
  super();
@@ -19,6 +20,7 @@ let LoginButton = class LoginButton extends LitElement {
19
20
  this.title = 'authenticate';
20
21
  this.buttonLabel = 'Authenticate';
21
22
  this.redirectUrl = '';
23
+ this.textLink = false;
22
24
  }
23
25
  updated() {
24
26
  if (this.oauthLogin) {
@@ -33,11 +35,15 @@ let LoginButton = class LoginButton extends LitElement {
33
35
  return out;
34
36
  }
35
37
  anonView() {
38
+ let action = html ` <sl-button @click="${this.openAuthModal}">
39
+ <sl-icon name="key" slot="prefix" style="font-size: 1rem"></sl-icon>
40
+ ${this.buttonLabel}
41
+ </sl-button>`;
42
+ if (this.textLink) {
43
+ action = html `<a href="#" @click="${this.openAuthModal}"><strong>${this.buttonLabel}</strong></a>`;
44
+ }
36
45
  return html `
37
- <sl-button @click="${this.openAuthModal}">
38
- <sl-icon name="key" slot="prefix" style="font-size: 1rem"></sl-icon>
39
- ${this.buttonLabel}
40
- </sl-button>
46
+ ${action}
41
47
  <sl-dialog id="auth-dialog" style="--width: 600px" no-header>
42
48
  <div style="padding-top: 20px;">
43
49
  <pb33f-oauth-login title="${this.title}"></pb33f-oauth-login>
@@ -84,7 +90,7 @@ let LoginButton = class LoginButton extends LitElement {
84
90
  this.authDialog.show();
85
91
  }
86
92
  };
87
- LoginButton.styles = [tooltipCss, buttonCss, modalCss, loginButtonCss];
93
+ LoginButton.styles = [tooltipCss, buttonCss, modalCss, loginButtonCss, linksCss];
88
94
  __decorate([
89
95
  query('#auth-dialog')
90
96
  ], LoginButton.prototype, "authDialog", void 0);
@@ -97,6 +103,9 @@ __decorate([
97
103
  __decorate([
98
104
  property()
99
105
  ], LoginButton.prototype, "redirectUrl", void 0);
106
+ __decorate([
107
+ property({ type: Boolean })
108
+ ], LoginButton.prototype, "textLink", void 0);
100
109
  __decorate([
101
110
  query('pb33f-oauth-login')
102
111
  ], LoginButton.prototype, "oauthLogin", void 0);
@@ -1,9 +1,10 @@
1
1
  import { LitElement } from "lit";
2
+ import { AuthController } from "../../controllers/auth-controller";
2
3
  export declare class LoginPanel extends LitElement {
3
4
  static styles: import("lit").CSSResult[];
4
5
  title: string;
5
6
  redirect: string;
6
- private controller;
7
+ controller: AuthController;
7
8
  constructor();
8
9
  willUpdate(): void;
9
10
  render(): import("lit-html").TemplateResult<1> | undefined;
@@ -6,12 +6,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { html, LitElement } from "lit";
8
8
  import { customElement, property } from "lit/decorators.js";
9
- import { AuthController } from "../../controllers/auth-controller";
10
9
  import loginButtonCss from "./login-button.css";
11
10
  let LoginPanel = class LoginPanel extends LitElement {
12
11
  constructor() {
13
12
  super();
14
- this.controller = new AuthController(this);
15
13
  this.title = 'authenticate';
16
14
  this.redirect = '/';
17
15
  }
@@ -40,6 +38,9 @@ __decorate([
40
38
  __decorate([
41
39
  property()
42
40
  ], LoginPanel.prototype, "redirect", void 0);
41
+ __decorate([
42
+ property()
43
+ ], LoginPanel.prototype, "controller", void 0);
43
44
  LoginPanel = __decorate([
44
45
  customElement('pb33f-login-panel')
45
46
  ], LoginPanel);
@@ -25,7 +25,7 @@ export default css `
25
25
 
26
26
  .no-values {
27
27
  height: 600px;
28
- width: 500px;
28
+ width: 70%;
29
29
  margin: 0 auto;
30
30
  padding-top: 50px;
31
31
  text-align: center;
@@ -21,5 +21,7 @@ export declare class Paginator extends LitElement {
21
21
  previousPage(event: CustomEvent): void;
22
22
  calcTotalPages(): number;
23
23
  protected willUpdate(): void;
24
+ startSparks(): void;
25
+ stopSparks(): void;
24
26
  render(): import("lit-html").TemplateResult<1>;
25
27
  }
@@ -83,15 +83,15 @@ let Paginator = class Paginator extends LitElement {
83
83
  }
84
84
  this.renderValues = this.values?.slice(this.paginatorNavigator.getRangeStart(), this.paginatorNavigator.getRangeEnd());
85
85
  }
86
+ startSparks() {
87
+ this.sparks.startAnimation();
88
+ }
89
+ stopSparks() {
90
+ this.sparks.stopAnimation();
91
+ }
86
92
  render() {
87
93
  this.sparks.isError = this.invalid;
88
- if (this.sparks.animating) {
89
- this.sparks.stopAnimation();
90
- }
91
94
  if (this.renderValues?.length === 0 || !this.renderValues) {
92
- if (!this.sparks.animating) {
93
- this.sparks.startAnimation();
94
- }
95
95
  if (!this.hideSparks) {
96
96
  return html `
97
97
  <div class="no-values ${this.invalid ? 'error' : ''}" style="position: relative">
@@ -73,6 +73,12 @@ let ProblemsOverview = class ProblemsOverview extends LitElement {
73
73
  this.problemOverviewGroups = this.buildProblemOverviewGroups(value);
74
74
  this.paginator.values = this.problemOverviewGroups;
75
75
  this.paginator.itemsPerPage = 10;
76
+ if (this.problemList.length <= 0) {
77
+ this.paginator.startSparks();
78
+ }
79
+ else {
80
+ this.paginator.stopSparks();
81
+ }
76
82
  }
77
83
  render() {
78
84
  if (this.unavailable) {
@@ -6,6 +6,7 @@ export declare class PixelSparks extends LitElement {
6
6
  private ctx;
7
7
  private canvas;
8
8
  private animationTimer;
9
+ private animationFrameId;
9
10
  isError: boolean;
10
11
  animating: boolean;
11
12
  static styles: import("lit").CSSResult;
@@ -9,9 +9,10 @@ import { css, html, LitElement } from "lit";
9
9
  let PixelSparks = class PixelSparks extends LitElement {
10
10
  constructor() {
11
11
  super();
12
+ this.animationFrameId = null;
12
13
  this.sparkArray = [];
13
- this.gravity = 0.0001;
14
- this.spawnRate = 70;
14
+ this.gravity = 0.005;
15
+ this.spawnRate = 50;
15
16
  this.isError = false;
16
17
  this.animating = false;
17
18
  }
@@ -26,39 +27,52 @@ let PixelSparks = class PixelSparks extends LitElement {
26
27
  }
27
28
  }
28
29
  startAnimation() {
30
+ // Only start if not already animating
29
31
  if (!this.animating) {
30
32
  this.animationTimer = setInterval(() => this.spawnSpark(), 1000 / this.spawnRate);
31
- this.animateSparks();
32
33
  this.animating = true;
34
+ this.animateSparks();
33
35
  }
34
36
  }
35
37
  stopAnimation() {
36
- if (this.animating) {
37
- clearInterval(this.animationTimer);
38
- this.animating = false;
38
+ this.animating = false;
39
+ clearInterval(this.animationTimer);
40
+ // Cancel any pending animation frame
41
+ if (this.animationFrameId !== null) {
42
+ cancelAnimationFrame(this.animationFrameId);
43
+ this.animationFrameId = null;
44
+ }
45
+ this.sparkArray = [];
46
+ // Clear the canvas one last time
47
+ if (this.ctx && this.canvas) {
48
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
39
49
  }
40
50
  }
41
51
  getRandomBetween(min, max) {
42
52
  return Math.random() * (max - min) + min;
43
53
  }
44
54
  spawnSpark() {
45
- let color = Math.random() > 0.5 ? 'rgb(248, 58, 255)' : 'rgb(98, 196, 255)';
46
- if (this.isError) {
47
- // create a color between
48
- color = Math.random() > 0.5 ? 'rgb(255, 60, 116)' : 'rgb(157, 26, 65)';
55
+ if (this.animating) {
56
+ let color = Math.random() > 0.5 ? 'rgb(248, 58, 255)' : 'rgb(98, 196, 255)';
57
+ if (this.isError) {
58
+ // create a color between
59
+ color = Math.random() > 0.5 ? 'rgb(255, 60, 116)' : 'rgb(157, 26, 65)';
60
+ }
61
+ this.sparkArray.push({
62
+ x: Math.random() * this.canvas.width,
63
+ y: -2,
64
+ size: 1,
65
+ color: color,
66
+ velocityY: this.getRandomBetween(0.05, 0.3),
67
+ lifetime: 150,
68
+ initialLifetime: 150,
69
+ opacity: 1
70
+ });
49
71
  }
50
- this.sparkArray.push({
51
- x: Math.random() * this.canvas.width,
52
- y: -2,
53
- size: 1,
54
- color: color,
55
- velocityY: this.getRandomBetween(0.05, 0.3),
56
- lifetime: 300,
57
- initialLifetime: 300,
58
- opacity: 1
59
- });
60
72
  }
61
73
  animateSparks() {
74
+ if (!this.animating)
75
+ return;
62
76
  this.ctx?.clearRect(0, 0, this.canvas?.width, this.canvas?.height);
63
77
  this.sparkArray = this.sparkArray.filter(spark => spark.lifetime > 0);
64
78
  for (let spark of this.sparkArray) {
@@ -68,7 +82,8 @@ let PixelSparks = class PixelSparks extends LitElement {
68
82
  spark.lifetime--;
69
83
  spark.opacity = spark.lifetime / spark.initialLifetime;
70
84
  }
71
- requestAnimationFrame(() => this.animateSparks());
85
+ // Store the ID so we can cancel it later
86
+ this.animationFrameId = requestAnimationFrame(() => this.animateSparks());
72
87
  }
73
88
  drawSpark(spark) {
74
89
  this.ctx.globalAlpha = spark.opacity; // Set transparency level
@@ -4,14 +4,14 @@ export default css `
4
4
  position: absolute;
5
5
  bottom: 8px;
6
6
  left: 0;
7
- width: 100%;
8
- height: 20px;
7
+ width: calc(100% - 6px);
8
+ height: 22px;
9
9
  background: var(--background-color);
10
- border: 1px dashed var(--secondary-color);
10
+ border-top: 1px dashed var(--secondary-color);
11
11
  z-index: 100;
12
12
  border-bottom: none;
13
- font-size: 0.8rem;
14
- padding: 4px 0 0 5px;
13
+ font-size: 0.9rem;
14
+ padding: 4px 0 2px 5px;
15
15
  vertical-align: middle;
16
16
 
17
17
  }
@@ -27,18 +27,20 @@ export default css `
27
27
  }
28
28
 
29
29
  .error-icon {
30
- color: var(--error-color);
30
+ color: var(--font-color);
31
31
  vertical-align: middle;
32
32
  }
33
33
 
34
34
  .warning {
35
- border: 1px dashed var(--warn-color);
35
+ border-top: 1px dashed var(--warn-color);
36
36
  border-bottom: none;
37
37
  }
38
38
 
39
39
  .error {
40
- border: 1px dashed var(--error-color);
40
+ border-top: 1px solid var(--error-color);
41
+ background-color: var(--error-color-dimmed);
41
42
  border-bottom: none;
43
+ color: var(--font-color)
42
44
  }
43
45
 
44
46
  strong {
@@ -4,9 +4,11 @@ export declare class StatusBar extends LitElement {
4
4
  static styles: import("lit").CSSResult[];
5
5
  visible: boolean;
6
6
  callsRemaining: number;
7
+ authenticated: boolean;
7
8
  dialog: SlDialog;
8
9
  constructor();
9
10
  openDialog(): void;
10
11
  closeDialog(): void;
12
+ authenticate(): void;
11
13
  render(): import("lit-html").TemplateResult<1> | undefined;
12
14
  }
@@ -9,11 +9,14 @@ import { html, LitElement } from "lit";
9
9
  import buttonCss from "../../css/button.css.js";
10
10
  import statusBarCss from "./status-bar.css.js";
11
11
  import linksCss from "../../css/links.css.js";
12
+ import dialogCss from "../../css/dialog.css";
13
+ import { OpenAuthentication } from "../../events/doctor";
12
14
  let StatusBar = class StatusBar extends LitElement {
13
15
  constructor() {
14
16
  super();
15
17
  this.visible = false;
16
18
  this.callsRemaining = 0;
19
+ this.authenticated = false;
17
20
  }
18
21
  openDialog() {
19
22
  this.dialog.show();
@@ -21,6 +24,11 @@ let StatusBar = class StatusBar extends LitElement {
21
24
  closeDialog() {
22
25
  this.dialog.hide();
23
26
  }
27
+ authenticate() {
28
+ this.dispatchEvent(new Event(OpenAuthentication, {
29
+ bubbles: true
30
+ }));
31
+ }
24
32
  render() {
25
33
  if (this.visible) {
26
34
  let clazz = '';
@@ -41,28 +49,30 @@ let StatusBar = class StatusBar extends LitElement {
41
49
  }
42
50
  return html `
43
51
  <div class="status-bar ${clazz}">
44
- <sl-dialog label="Credit upgrade coming soon!" class="dialog-overview">
45
- <p>To get more credit for the doctor, you will need to create an account. This feature is coming soon.</p>
46
- <p>
47
- In the meantime please wait 24 hours for your credit to be reset.
52
+ <sl-dialog label="Purchase Credit" class="dialog-overview">
53
+ <p>Still working on this, coming soon!
48
54
  </p>
49
55
  <sl-button slot="footer" variant="primary" @click="${this.closeDialog}">Close</sl-button>
50
56
  </sl-dialog>
51
57
  <sl-icon name="${icon}" class="${clazzIcon}"></sl-icon>
52
- <span class="status-text">Credits remaining: <strong>${this.callsRemaining}</strong></span> |
53
- <span class="action-text">${actionText}</span>
54
- ${this.callsRemaining <= 0 ? html ` | <a href="#" @click="${this.openDialog}"><strong>Get more credit</strong></a>` : ''}
58
+ <span class="status-text"><strong>Credits remaining: ${this.callsRemaining}</strong></span> |
59
+ <span class="action-text"><strong>${actionText}</strong></span>
60
+ ${this.callsRemaining <= 0 && !this.authenticated ? html `| <pb33f-login-button title="Get More Credit" buttonLabel="Authenticate for more credit" textLink></pb33f-login-button>` : ''}
61
+ ${this.callsRemaining <= 0 && this.authenticated ? html `| <a href="#" @click="${this.openDialog}"><strong>Purchase Credit</strong></a>` : ''}
55
62
  </div>`;
56
63
  }
57
64
  }
58
65
  };
59
- StatusBar.styles = [statusBarCss, linksCss, buttonCss];
66
+ StatusBar.styles = [statusBarCss, linksCss, buttonCss, dialogCss];
60
67
  __decorate([
61
68
  property({ type: Boolean })
62
69
  ], StatusBar.prototype, "visible", void 0);
63
70
  __decorate([
64
71
  property({ type: Number })
65
72
  ], StatusBar.prototype, "callsRemaining", void 0);
73
+ __decorate([
74
+ property({ type: Boolean })
75
+ ], StatusBar.prototype, "authenticated", void 0);
66
76
  __decorate([
67
77
  query('sl-dialog')
68
78
  ], StatusBar.prototype, "dialog", void 0);
@@ -222,6 +222,7 @@ export declare class TheDoctor extends LitElement {
222
222
  updateExplorerDivider(): void;
223
223
  updateRolodexDivider(): void;
224
224
  updateRefmapBag(currentPath: string | undefined, result: Reference[]): void;
225
+ creditEmpty(e: CustomEvent): void;
225
226
  platformUnavailable(error: PlatformError | null): void;
226
227
  builtInRulesetSelected(): void;
227
228
  runDiagnostics(): void;
@@ -16,7 +16,7 @@ import '@shoelace-style/shoelace/dist/components/avatar/avatar.js';
16
16
  import { customElement, property, query, state } from "lit/decorators.js";
17
17
  import { html, LitElement } from "lit";
18
18
  import { SpecEditor } from "../editor/editor.js";
19
- import { ActiveView, AddToast, ArchiveURLRequested, BuiltInRulesetChanged, CustomRulesetEnabled, DocumentReferenceClicked, EditorClicked, EditorUpdated, ExplorerEqualizerChanged, ExplorerEqualizerFiltered, ExplorerNodeClicked, ExportRuleset, LoadRenderedNodeIntoInspector, ModelTreeNodeClicked, NodeReferenceClicked, NukeWorkspaceEvent, OpenProblemDrawer, OpenSettings, ProblemClicked, RolodexRootFileSelected, RolodexTreeNodeClicked, RuleClicked, RulesetSaved, RuleViolationClicked, StartSessionFailed, } from "../../events/doctor.js";
19
+ import { ActiveView, AddToast, ArchiveURLRequested, BuiltInRulesetChanged, CreditEmpty, CustomRulesetEnabled, DocumentReferenceClicked, EditorClicked, EditorUpdated, ExplorerEqualizerChanged, ExplorerEqualizerFiltered, ExplorerNodeClicked, ExportRuleset, LoadRenderedNodeIntoInspector, ModelTreeNodeClicked, NodeReferenceClicked, NukeWorkspaceEvent, OpenProblemDrawer, OpenSettings, ProblemClicked, RolodexRootFileSelected, RolodexTreeNodeClicked, RuleClicked, RulesetSaved, RuleViolationClicked, StartSessionFailed, } from "../../events/doctor.js";
20
20
  import { ProblemDetailsDrawer } from "../problem-list/details-drawer.js";
21
21
  import { CreateBagManager } from "@pb33f/saddlebag";
22
22
  import { LintingService } from "../../services/linting-service.js";
@@ -248,6 +248,8 @@ let TheDoctor = class TheDoctor extends LitElement {
248
248
  // @ts-ignore
249
249
  this.authController.addEventListener(StartSessionFailed, this.platformUnavailable.bind(this));
250
250
  this.timeVortex.historyPicker.addEventListener(OpenSettings, this.openSettings.bind(this));
251
+ // @ts-ignore
252
+ this.authController.addEventListener(CreditEmpty, this.creditEmpty.bind(this));
251
253
  //@ts-ignore
252
254
  this.addEventListener(LoadRenderedNodeIntoInspector, this.loadRenderedNodeIntoInspector.bind(this));
253
255
  // hijack navigation buttons.
@@ -398,6 +400,9 @@ let TheDoctor = class TheDoctor extends LitElement {
398
400
  }
399
401
  this.referenceMapBag?.set(ReferenceMapBag, refMap);
400
402
  }
403
+ creditEmpty(e) {
404
+ this.platformUnavailable(e.detail.error);
405
+ }
401
406
  platformUnavailable(error) {
402
407
  if (!this.unavailable) {
403
408
  this.loadingOverlay?.hide();
@@ -436,6 +441,7 @@ let TheDoctor = class TheDoctor extends LitElement {
436
441
  this.diagnosticController.lintSpec('', urlParam);
437
442
  return;
438
443
  }
444
+ // todo: this needs work man. I want to see all these settimeouts gone brother.
439
445
  setTimeout(() => {
440
446
  // check for a history
441
447
  this.timeVortex.doctor = this;
@@ -694,6 +700,7 @@ let TheDoctor = class TheDoctor extends LitElement {
694
700
  ${modelTree}
695
701
  `;
696
702
  if (this.authController.state && this.authController.state.authenticated) {
703
+ this.statusBar.authenticated = true;
697
704
  }
698
705
  return html `
699
706
  ${this.uploadArchive}
@@ -19,7 +19,7 @@ export declare class AuthController extends EventTarget {
19
19
  private startSession;
20
20
  associateBroker(brokerId: string): Promise<boolean>;
21
21
  authGithub(e: CustomEvent<AuthenticationMeta>): void;
22
- logout(e: CustomEvent<AuthenticationMeta>): void;
22
+ logout(): void;
23
23
  private notifyStateChange;
24
24
  checkState(): Promise<AuthenticationState>;
25
25
  }
@@ -1,4 +1,4 @@
1
- import { AuthenticationGithubRequested, AuthenticationStateChange, LogoutRequested, NukeWorkspaceEvent, StartSessionFailed } from "../events/doctor.js";
1
+ import { AuthenticationGithubRequested, AuthenticationStateChange, CreditEmpty, LogoutRequested, NukeWorkspaceEvent, StartSessionFailed } from "../events/doctor.js";
2
2
  import { AuthService } from "../services/auth-service.js";
3
3
  import { HeaderService } from "../services/header-service";
4
4
  export class AuthController extends EventTarget {
@@ -56,8 +56,19 @@ export class AuthController extends EventTarget {
56
56
  this.sessionCallback.call(this.hosts[this.callbackIdx], session);
57
57
  this.hosts[this.callbackIdx].requestUpdate();
58
58
  }
59
- }).catch((err) => {
60
- console.error("something went wrong with starting session", err);
59
+ }).catch((e) => {
60
+ // determine if this is an API failure, or a credit issue.
61
+ if (e.instance == 'https://pb33f.io/errors/no-credit-remaining') {
62
+ this.dispatchEvent(new CustomEvent(CreditEmpty, {
63
+ bubbles: true,
64
+ composed: true,
65
+ detail: {
66
+ error: e
67
+ }
68
+ }));
69
+ return;
70
+ }
71
+ console.error("something went wrong with starting session", e);
61
72
  this.dispatchEvent(new Event(StartSessionFailed));
62
73
  });
63
74
  };
@@ -89,7 +100,7 @@ export class AuthController extends EventTarget {
89
100
  });
90
101
  const session = await sessionJSON.json();
91
102
  if (session.type && session.title && session.status) {
92
- reject();
103
+ reject(session);
93
104
  }
94
105
  resolve(session);
95
106
  }
@@ -125,17 +136,17 @@ export class AuthController extends EventTarget {
125
136
  window.location.href = this.doctorEndpoint + '/auth/github/start';
126
137
  }
127
138
  }
128
- logout(e) {
139
+ logout() {
129
140
  AuthService.logout().then(() => {
130
- if (e.detail.redirectURL != '') {
131
- this.dispatchEvent(new CustomEvent(NukeWorkspaceEvent, {
132
- bubbles: true,
133
- composed: true,
134
- detail: {
135
- resetFiles: false
136
- }
137
- }));
138
- }
141
+ //if (e.detail.redirectURL != '') {
142
+ this.dispatchEvent(new CustomEvent(NukeWorkspaceEvent, {
143
+ bubbles: true,
144
+ composed: true,
145
+ detail: {
146
+ resetFiles: true
147
+ }
148
+ }));
149
+ // }
139
150
  });
140
151
  }
141
152
  notifyStateChange(state) {
@@ -8,6 +8,7 @@ export class DocsController extends EventTarget {
8
8
  this.doc = doc;
9
9
  }
10
10
  fetchDocs() {
11
+ //return;
11
12
  this.doc.activitySpinner.show();
12
13
  const url = new URL(window.location.href);
13
14
  const urlParam = url.searchParams.get('url');