@ansiversa/components 0.0.142 → 0.0.143

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/index.ts CHANGED
@@ -35,6 +35,7 @@ export { default as AvTableToolbar } from './src/AvTableToolbar.astro';
35
35
  export { default as AvTablePagination } from './src/AvTablePagination.astro';
36
36
  export { default as QuizSummary } from './src/Summary/QuizSummary.astro';
37
37
  export { default as FlashNoteSummary } from './src/Summary/FlashNoteSummary.astro';
38
+ export { default as StudyPlannerSummary } from './src/Summary/StudyPlannerSummary.astro';
38
39
  export { default as ResumeBuilderSummary } from './src/Summary/ResumeBuilderSummary.astro';
39
40
  export { default as PortfolioCreatorSummary } from './src/Summary/PortfolioCreatorSummary.astro';
40
41
  export { default as AvImageUploader } from "./src/components/media/AvImageUploader.astro";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ansiversa/components",
3
- "version": "0.0.142",
3
+ "version": "0.0.143",
4
4
  "description": "Shared UI components and layouts for the Ansiversa ecosystem",
5
5
  "type": "module",
6
6
  "exports": {
@@ -0,0 +1,95 @@
1
+ ---
2
+ import { AvButton, AvCard } from "@ansiversa/components";
3
+ import type { StudyPlannerDashboardSummaryV1 } from "./types";
4
+ import { buildAppUrl } from "../utils/appUrls";
5
+
6
+ interface Props {
7
+ summary: StudyPlannerDashboardSummaryV1;
8
+ }
9
+
10
+ const { summary } = Astro.props as Props;
11
+
12
+ const formatDateTime = (value: string | null, fallback = "Not yet") => {
13
+ if (!value) return fallback;
14
+ const parsed = new Date(value);
15
+ return Number.isNaN(parsed.getTime()) ? fallback : parsed.toLocaleString();
16
+ };
17
+
18
+ const appBaseUrl = buildAppUrl(summary.appId);
19
+ const plansUrl = buildAppUrl(summary.appId, "/plans");
20
+ const trackOpenPayload = JSON.stringify({
21
+ id: summary.appId,
22
+ key: summary.appId,
23
+ name: "Study Planner",
24
+ description: "Study Planner",
25
+ url: appBaseUrl,
26
+ });
27
+
28
+ const lastPlan = summary.recent.recentPlans[0];
29
+ const lastTask = summary.recent.recentTasks[0];
30
+ const lastLog = summary.recent.recentLogs[0];
31
+ ---
32
+
33
+ <section class="av-auth-stack-lg">
34
+ <div class="av-form-row">
35
+ <div class="av-auth-stack-xxs">
36
+ <p class="av-text-soft">Last plan: {formatDateTime(lastPlan?.updatedAt ?? null)}</p>
37
+ </div>
38
+ <div class="av-row-wrap">
39
+ <AvButton
40
+ href={appBaseUrl}
41
+ size="sm"
42
+ onclick={`window.dispatchEvent(new CustomEvent('ansiversa:app-opened', { detail: ${trackOpenPayload} }))`}
43
+ >
44
+ Open App ->
45
+ </AvButton>
46
+ <AvButton href={plansUrl} size="sm" variant="ghost">View plans</AvButton>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="av-grid-auto av-grid-auto--260">
51
+ <AvCard variant="soft" className="av-card--fullheight">
52
+ <div class="av-auth-stack-xxs">
53
+ <p class="av-card-heading">Plans</p>
54
+ <h3 class="av-app-card-title">{summary.totals.plansTotal}</h3>
55
+ <p class="av-text-soft">{summary.totals.plansActive} active</p>
56
+ </div>
57
+ </AvCard>
58
+ <AvCard variant="soft" className="av-card--fullheight">
59
+ <div class="av-auth-stack-xxs">
60
+ <p class="av-card-heading">Tasks</p>
61
+ <h3 class="av-app-card-title">{summary.totals.tasksTotal}</h3>
62
+ <p class="av-text-soft">{summary.totals.tasksCompleted} completed</p>
63
+ </div>
64
+ </AvCard>
65
+ <AvCard variant="soft" className="av-card--fullheight">
66
+ <div class="av-auth-stack-xxs">
67
+ <p class="av-card-heading">Due today</p>
68
+ <h3 class="av-app-card-title">{summary.totals.tasksDueToday}</h3>
69
+ <p class="av-text-soft">{summary.totals.logsThisWeek} logs this week</p>
70
+ </div>
71
+ </AvCard>
72
+ <AvCard variant="soft" className="av-card--fullheight">
73
+ <div class="av-auth-stack-xxs">
74
+ <p class="av-card-heading">Bookmarks</p>
75
+ <h3 class="av-app-card-title">{summary.totals.bookmarksTotal}</h3>
76
+ <p class="av-text-soft">Last log: {formatDateTime(lastLog?.createdAt ?? null)}</p>
77
+ </div>
78
+ </AvCard>
79
+ </div>
80
+
81
+ <div class="av-grid-auto av-grid-auto--260">
82
+ <AvCard variant="soft" className="av-card--fullheight">
83
+ <div class="av-auth-stack-xxs">
84
+ <p class="av-card-heading">Recent plan</p>
85
+ <p class="av-text-strong">{lastPlan?.title ?? "No recent plans"}</p>
86
+ </div>
87
+ </AvCard>
88
+ <AvCard variant="soft" className="av-card--fullheight">
89
+ <div class="av-auth-stack-xxs">
90
+ <p class="av-card-heading">Recent task</p>
91
+ <p class="av-text-strong">{lastTask?.title ?? "No recent tasks"}</p>
92
+ </div>
93
+ </AvCard>
94
+ </div>
95
+ </section>
@@ -64,3 +64,35 @@ export type PortfolioDashboardSummaryV1 = {
64
64
  };
65
65
  completionHint?: number;
66
66
  };
67
+
68
+ export type StudyPlannerDashboardSummaryV1 = {
69
+ appId: "study-planner";
70
+ version: 1;
71
+ updatedAt: string;
72
+ totals: {
73
+ plansTotal: number;
74
+ plansActive: number;
75
+ tasksTotal: number;
76
+ tasksCompleted: number;
77
+ tasksDueToday: number;
78
+ logsThisWeek: number;
79
+ bookmarksTotal: number;
80
+ };
81
+ recent: {
82
+ recentPlans: Array<{
83
+ id: number;
84
+ title: string;
85
+ updatedAt: string | null;
86
+ }>;
87
+ recentTasks: Array<{
88
+ id: number;
89
+ title: string;
90
+ updatedAt: string | null;
91
+ }>;
92
+ recentLogs: Array<{
93
+ id: number;
94
+ title: string;
95
+ createdAt: string | null;
96
+ }>;
97
+ };
98
+ };
@@ -3,6 +3,7 @@ const ROOT_DOMAIN = "ansiversa.com";
3
3
  const MINI_APP_SLUGS = new Set([
4
4
  "quiz",
5
5
  "flashnote",
6
+ "study-planner",
6
7
  "resume-builder",
7
8
  "portfolio-creator",
8
9
  ]);