@legenki/studio-core 0.2.0 → 0.3.0

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.
package/README.md CHANGED
@@ -134,7 +134,7 @@ npm version patch # or minor / major
134
134
  git push && git push --tags
135
135
  ```
136
136
 
137
- That runs lint and tests, then publishes to npm with provenance. Needs an
137
+ That runs lint and tests, then publishes to npm. Needs an
138
138
  `NPM_TOKEN` repo secret.
139
139
 
140
140
  Because all four studios pin this package, a breaking change here should be a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legenki/studio-core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Shared auth, paywall and utilities for the Legenki browser studios (Grafema, Ritmo, Divix, Lumen).",
5
5
  "type": "module",
6
6
  "license": "ISC",
package/src/paywall.js CHANGED
@@ -23,10 +23,10 @@ let _selectedPlan = 'yearly';
23
23
  * @property {string} appName e.g. "Grafema" — titles the modal.
24
24
  * @property {string} [subtitle] One-line summary of what Pro unlocks.
25
25
  * @property {string[]} [features] Bullet list shown in the modal.
26
- * @property {string} [monthly] Display price, e.g. "$5".
26
+ * @property {string} [monthly] Display price, e.g. "$8".
27
27
  * @property {string} [yearly] Display price, e.g. "$40".
28
- * @property {string} [yearlyPerMonth] e.g. "$3.33 / month".
29
- * @property {string} [yearlyNote] e.g. "Yearly · save 33%".
28
+ * @property {string} [yearlyPerMonth] Override; derived from `yearly` if unset.
29
+ * @property {string} [yearlyNote] Override; derived from both prices if unset.
30
30
  */
31
31
 
32
32
  /** @type {Required<PaywallConfig>} */
@@ -34,12 +34,37 @@ const config = {
34
34
  appName: 'Pro',
35
35
  subtitle: '',
36
36
  features: [],
37
- monthly: '$5',
37
+ monthly: '$8',
38
38
  yearly: '$40',
39
- yearlyPerMonth: '$3.33 / month',
40
- yearlyNote: 'Yearly · save 33%',
39
+ // Left unset by default: both are derived from the prices below, so a price
40
+ // change cannot leave a stale "save 33%" sitting next to it. Pass them
41
+ // explicitly only to override the wording.
42
+ yearlyPerMonth: '',
43
+ yearlyNote: '',
41
44
  };
42
45
 
46
+ /**
47
+ * Yearly savings, derived from the two prices rather than hardcoded.
48
+ * Falls back to the caller's override when one was supplied.
49
+ */
50
+ function yearlyNote() {
51
+ if (config.yearlyNote) return config.yearlyNote;
52
+ const m = Number(String(config.monthly).replace(/[^0-9.]/g, ''));
53
+ const y = Number(String(config.yearly).replace(/[^0-9.]/g, ''));
54
+ if (!m || !y) return 'Yearly';
55
+ const percent = Math.round(((m * 12 - y) / (m * 12)) * 100);
56
+ return percent > 0 ? `Yearly · save ${percent}%` : 'Yearly';
57
+ }
58
+
59
+ /** Effective monthly cost of the yearly plan, e.g. "$3.33 / month". */
60
+ function yearlyPerMonth() {
61
+ if (config.yearlyPerMonth) return config.yearlyPerMonth;
62
+ const y = Number(String(config.yearly).replace(/[^0-9.]/g, ''));
63
+ if (!y) return '';
64
+ const symbol = String(config.yearly).replace(/[0-9.,\s]/g, '') || '$';
65
+ return `${symbol}${(y / 12).toFixed(2)} / month`;
66
+ }
67
+
43
68
  /**
44
69
  * Sets the app-specific copy. Call once at startup, before openPaywall().
45
70
  * Re-configuring discards any modal already built so the new copy takes effect.
@@ -92,9 +117,9 @@ function getModal() {
92
117
  <div class="paywall-plan-period">per month</div>
93
118
  </div>
94
119
  <div class="paywall-plan selected" data-plan="yearly">
95
- <div class="paywall-plan-label">${escapeHtml(config.yearlyNote)}</div>
120
+ <div class="paywall-plan-label">${escapeHtml(yearlyNote())}</div>
96
121
  <div class="paywall-plan-amount">${escapeHtml(config.yearly)}</div>
97
- <div class="paywall-plan-period">${escapeHtml(config.yearlyPerMonth)}</div>
122
+ <div class="paywall-plan-period">${escapeHtml(yearlyPerMonth())}</div>
98
123
  </div>
99
124
  </div>
100
125
  <button class="paywall-cta btn btn-accent">${escapeHtml(ctaLabel())}</button>