@contractspec/lib.example-shared-ui 6.0.6 → 6.0.10

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.
Files changed (82) hide show
  1. package/.turbo/turbo-build.log +90 -84
  2. package/AGENTS.md +43 -25
  3. package/CHANGELOG.md +24 -0
  4. package/README.md +63 -35
  5. package/dist/EvolutionDashboard.js +9 -9
  6. package/dist/EvolutionSidebar.js +15 -15
  7. package/dist/LocalDataIndicator.js +3 -3
  8. package/dist/MarkdownView.d.ts +0 -7
  9. package/dist/MarkdownView.js +76 -172
  10. package/dist/PersonalizationInsights.js +12 -12
  11. package/dist/SaveToStudioButton.js +2 -2
  12. package/dist/SpecDrivenTemplateShell.d.ts +1 -1
  13. package/dist/SpecDrivenTemplateShell.js +10 -10
  14. package/dist/SpecEditorPanel.js +3 -3
  15. package/dist/TemplateShell.js +10 -10
  16. package/dist/browser/EvolutionDashboard.js +9 -9
  17. package/dist/browser/EvolutionSidebar.js +15 -15
  18. package/dist/browser/LocalDataIndicator.js +3 -3
  19. package/dist/browser/MarkdownView.js +76 -172
  20. package/dist/browser/PersonalizationInsights.js +12 -12
  21. package/dist/browser/SaveToStudioButton.js +2 -2
  22. package/dist/browser/SpecDrivenTemplateShell.js +10 -10
  23. package/dist/browser/SpecEditorPanel.js +3 -3
  24. package/dist/browser/TemplateShell.js +10 -10
  25. package/dist/browser/hooks/index.js +29 -29
  26. package/dist/browser/index.js +193 -286
  27. package/dist/browser/lib/component-registry.js +1 -1
  28. package/dist/browser/markdown/formatPresentationName.js +9 -0
  29. package/dist/browser/markdown/useMarkdownPresentation.js +65 -0
  30. package/dist/hooks/index.d.ts +3 -3
  31. package/dist/hooks/index.js +29 -29
  32. package/dist/index.d.ts +12 -11
  33. package/dist/index.js +193 -286
  34. package/dist/lib/component-registry.js +1 -1
  35. package/dist/markdown/formatPresentationName.d.ts +1 -0
  36. package/dist/markdown/formatPresentationName.js +10 -0
  37. package/dist/markdown/useMarkdownPresentation.d.ts +21 -0
  38. package/dist/markdown/useMarkdownPresentation.js +66 -0
  39. package/dist/node/EvolutionDashboard.js +9 -9
  40. package/dist/node/EvolutionSidebar.js +15 -15
  41. package/dist/node/LocalDataIndicator.js +3 -3
  42. package/dist/node/MarkdownView.js +76 -172
  43. package/dist/node/PersonalizationInsights.js +12 -12
  44. package/dist/node/SaveToStudioButton.js +2 -2
  45. package/dist/node/SpecDrivenTemplateShell.js +10 -10
  46. package/dist/node/SpecEditorPanel.js +3 -3
  47. package/dist/node/TemplateShell.js +10 -10
  48. package/dist/node/hooks/index.js +29 -29
  49. package/dist/node/index.js +193 -286
  50. package/dist/node/lib/component-registry.js +1 -1
  51. package/dist/node/markdown/formatPresentationName.js +9 -0
  52. package/dist/node/markdown/useMarkdownPresentation.js +65 -0
  53. package/dist/utils/index.d.ts +1 -1
  54. package/package.json +40 -13
  55. package/src/EvolutionDashboard.tsx +415 -415
  56. package/src/EvolutionSidebar.tsx +245 -245
  57. package/src/LocalDataIndicator.tsx +28 -28
  58. package/src/MarkdownView.tsx +119 -372
  59. package/src/OverlayContextProvider.tsx +272 -272
  60. package/src/PersonalizationInsights.tsx +232 -232
  61. package/src/SaveToStudioButton.tsx +51 -51
  62. package/src/SpecDrivenTemplateShell.tsx +59 -59
  63. package/src/SpecEditorPanel.tsx +138 -138
  64. package/src/TemplateShell.tsx +50 -50
  65. package/src/bundles/ExampleTemplateBundle.ts +78 -78
  66. package/src/hooks/index.ts +3 -3
  67. package/src/hooks/useBehaviorTracking.ts +252 -252
  68. package/src/hooks/useEvolution.ts +437 -437
  69. package/src/hooks/useRegistryTemplates.ts +42 -42
  70. package/src/hooks/useSpecContent.ts +214 -214
  71. package/src/hooks/useWorkflowComposer.ts +567 -567
  72. package/src/index.ts +12 -11
  73. package/src/lib/component-registry.tsx +40 -40
  74. package/src/lib/runtime-context.tsx +31 -31
  75. package/src/lib/types.ts +57 -57
  76. package/src/markdown/formatPresentationName.ts +9 -0
  77. package/src/markdown/useMarkdownPresentation.ts +107 -0
  78. package/src/overlay-types.ts +15 -15
  79. package/src/utils/fetchPresentationData.ts +13 -13
  80. package/src/utils/generateSpecFromTemplate.ts +29 -29
  81. package/src/utils/index.ts +1 -1
  82. package/tsconfig.json +8 -8
@@ -1,24 +1,24 @@
1
- import type { ReactNode } from 'react';
2
1
  import {
3
- BundleProvider,
4
- BundleRenderer,
2
+ BundleProvider,
3
+ BundleRenderer,
5
4
  } from '@contractspec/lib.surface-runtime/react';
6
5
  import type { ResolvedSurfacePlan } from '@contractspec/lib.surface-runtime/runtime/resolve-bundle';
6
+ import type { ReactNode } from 'react';
7
7
  import { LocalDataIndicator } from './LocalDataIndicator';
8
8
  import {
9
- SaveToStudioButton,
10
- type SaveToStudioButtonProps,
9
+ SaveToStudioButton,
10
+ type SaveToStudioButtonProps,
11
11
  } from './SaveToStudioButton';
12
12
 
13
13
  export interface SpecDrivenTemplateShellProps {
14
- plan: ResolvedSurfacePlan;
15
- title: string;
16
- description?: string;
17
- sidebar?: ReactNode;
18
- actions?: ReactNode;
19
- children: ReactNode;
20
- showSaveAction?: boolean;
21
- saveProps?: SaveToStudioButtonProps;
14
+ plan: ResolvedSurfacePlan;
15
+ title: string;
16
+ description?: string;
17
+ sidebar?: ReactNode;
18
+ actions?: ReactNode;
19
+ children: ReactNode;
20
+ showSaveAction?: boolean;
21
+ saveProps?: SaveToStudioButtonProps;
22
22
  }
23
23
 
24
24
  /**
@@ -27,53 +27,53 @@ export interface SpecDrivenTemplateShellProps {
27
27
  * Requires @contractspec/lib.surface-runtime as peer dependency.
28
28
  */
29
29
  export function SpecDrivenTemplateShell({
30
- plan,
31
- title,
32
- description,
33
- sidebar,
34
- actions,
35
- showSaveAction = true,
36
- saveProps,
37
- children,
30
+ plan,
31
+ title,
32
+ description,
33
+ sidebar,
34
+ actions,
35
+ showSaveAction = true,
36
+ saveProps,
37
+ children,
38
38
  }: SpecDrivenTemplateShellProps) {
39
- const headerContent = (
40
- <header className="border-border bg-card rounded-2xl border p-6 shadow-sm">
41
- <div className="flex flex-wrap items-center justify-between gap-4">
42
- <div>
43
- <p className="text-muted-foreground text-sm font-semibold tracking-wide uppercase">
44
- ContractSpec Templates
45
- </p>
46
- <h1 className="text-3xl font-bold">{title}</h1>
47
- {description ? (
48
- <p className="text-muted-foreground mt-2 max-w-2xl text-sm">
49
- {description}
50
- </p>
51
- ) : null}
52
- </div>
53
- <div className="flex flex-col items-end gap-2">
54
- <LocalDataIndicator />
55
- {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
56
- </div>
57
- </div>
58
- {actions ? <div className="mt-4">{actions}</div> : null}
59
- </header>
60
- );
39
+ const headerContent = (
40
+ <header className="rounded-2xl border border-border bg-card p-6 shadow-sm">
41
+ <div className="flex flex-wrap items-center justify-between gap-4">
42
+ <div>
43
+ <p className="font-semibold text-muted-foreground text-sm uppercase tracking-wide">
44
+ ContractSpec Templates
45
+ </p>
46
+ <h1 className="font-bold text-3xl">{title}</h1>
47
+ {description ? (
48
+ <p className="mt-2 max-w-2xl text-muted-foreground text-sm">
49
+ {description}
50
+ </p>
51
+ ) : null}
52
+ </div>
53
+ <div className="flex flex-col items-end gap-2">
54
+ <LocalDataIndicator />
55
+ {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
56
+ </div>
57
+ </div>
58
+ {actions ? <div className="mt-4">{actions}</div> : null}
59
+ </header>
60
+ );
61
61
 
62
- const slotContent: Partial<Record<string, ReactNode>> = {
63
- header: headerContent,
64
- primary: <main className="space-y-4 p-2">{children}</main>,
65
- };
66
- if (sidebar != null) {
67
- slotContent.sidebar = (
68
- <aside className="border-border bg-card rounded-2xl border p-4">
69
- {sidebar}
70
- </aside>
71
- );
72
- }
62
+ const slotContent: Partial<Record<string, ReactNode>> = {
63
+ header: headerContent,
64
+ primary: <main className="space-y-4 p-2">{children}</main>,
65
+ };
66
+ if (sidebar != null) {
67
+ slotContent.sidebar = (
68
+ <aside className="rounded-2xl border border-border bg-card p-4">
69
+ {sidebar}
70
+ </aside>
71
+ );
72
+ }
73
73
 
74
- return (
75
- <BundleProvider plan={plan}>
76
- <BundleRenderer slotContent={slotContent} />
77
- </BundleProvider>
78
- );
74
+ return (
75
+ <BundleProvider plan={plan}>
76
+ <BundleRenderer slotContent={slotContent} />
77
+ </BundleProvider>
78
+ );
79
79
  }
@@ -1,27 +1,27 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useEffect } from 'react';
4
3
  import { Button, LoaderBlock } from '@contractspec/lib.design-system';
5
4
  import { Badge } from '@contractspec/lib.ui-kit-web/ui/badge';
6
- import type { TemplateId } from './lib/types';
5
+ import { useCallback, useEffect } from 'react';
7
6
  import { useSpecContent } from './hooks/useSpecContent';
7
+ import type { TemplateId } from './lib/types';
8
8
 
9
9
  export interface SpecEditorProps {
10
- projectId: string;
11
- type?: 'CAPABILITY' | 'DATAVIEW' | 'WORKFLOW' | 'POLICY' | 'COMPONENT';
12
- content: string;
13
- onChange: (content: string) => void;
14
- metadata?: Record<string, unknown>;
15
- onSave?: () => void;
16
- onValidate?: () => void;
10
+ projectId: string;
11
+ type?: 'CAPABILITY' | 'DATAVIEW' | 'WORKFLOW' | 'POLICY' | 'COMPONENT';
12
+ content: string;
13
+ onChange: (content: string) => void;
14
+ metadata?: Record<string, unknown>;
15
+ onSave?: () => void;
16
+ onValidate?: () => void;
17
17
  }
18
18
 
19
19
  export interface SpecEditorPanelProps {
20
- templateId: TemplateId;
21
- /** SpecEditor component passed as a prop (for dynamic import compatibility) */
22
- SpecEditor: React.ComponentType<SpecEditorProps>;
23
- /** Callback for logging actions */
24
- onLog?: (message: string) => void;
20
+ templateId: TemplateId;
21
+ /** SpecEditor component passed as a prop (for dynamic import compatibility) */
22
+ SpecEditor: React.ComponentType<SpecEditorProps>;
23
+ /** Callback for logging actions */
24
+ onLog?: (message: string) => void;
25
25
  }
26
26
 
27
27
  /**
@@ -29,137 +29,137 @@ export interface SpecEditorPanelProps {
29
29
  * Uses useSpecContent hook to manage spec persistence and validation.
30
30
  */
31
31
  export function SpecEditorPanel({
32
- templateId,
33
- SpecEditor,
34
- onLog,
32
+ templateId,
33
+ SpecEditor,
34
+ onLog,
35
35
  }: SpecEditorPanelProps) {
36
- const {
37
- content,
38
- loading,
39
- isDirty,
40
- validation,
41
- setContent,
42
- save,
43
- validate,
44
- reset,
45
- lastSaved,
46
- } = useSpecContent(templateId);
36
+ const {
37
+ content,
38
+ loading,
39
+ isDirty,
40
+ validation,
41
+ setContent,
42
+ save,
43
+ validate,
44
+ reset,
45
+ lastSaved,
46
+ } = useSpecContent(templateId);
47
47
 
48
- // Log when spec is loaded
49
- useEffect(() => {
50
- if (!loading && content) {
51
- onLog?.(`Spec loaded for ${templateId}`);
52
- }
53
- }, [loading, content, templateId, onLog]);
48
+ // Log when spec is loaded
49
+ useEffect(() => {
50
+ if (!loading && content) {
51
+ onLog?.(`Spec loaded for ${templateId}`);
52
+ }
53
+ }, [loading, content, templateId, onLog]);
54
54
 
55
- const handleSave = useCallback(() => {
56
- save();
57
- onLog?.('Spec saved locally');
58
- }, [save, onLog]);
55
+ const handleSave = useCallback(() => {
56
+ save();
57
+ onLog?.('Spec saved locally');
58
+ }, [save, onLog]);
59
59
 
60
- const handleValidate = useCallback(() => {
61
- const result = validate();
62
- if (result.valid) {
63
- onLog?.('Spec validation passed');
64
- } else {
65
- const errorCount = result.errors.filter(
66
- (e) => e.severity === 'error'
67
- ).length;
68
- const warnCount = result.errors.filter(
69
- (e) => e.severity === 'warning'
70
- ).length;
71
- onLog?.(`Spec validation: ${errorCount} errors, ${warnCount} warnings`);
72
- }
73
- }, [validate, onLog]);
60
+ const handleValidate = useCallback(() => {
61
+ const result = validate();
62
+ if (result.valid) {
63
+ onLog?.('Spec validation passed');
64
+ } else {
65
+ const errorCount = result.errors.filter(
66
+ (e) => e.severity === 'error'
67
+ ).length;
68
+ const warnCount = result.errors.filter(
69
+ (e) => e.severity === 'warning'
70
+ ).length;
71
+ onLog?.(`Spec validation: ${errorCount} errors, ${warnCount} warnings`);
72
+ }
73
+ }, [validate, onLog]);
74
74
 
75
- const handleReset = useCallback(() => {
76
- reset();
77
- onLog?.('Spec reset to template defaults');
78
- }, [reset, onLog]);
75
+ const handleReset = useCallback(() => {
76
+ reset();
77
+ onLog?.('Spec reset to template defaults');
78
+ }, [reset, onLog]);
79
79
 
80
- if (loading) {
81
- return <LoaderBlock label="Loading spec..." />;
82
- }
80
+ if (loading) {
81
+ return <LoaderBlock label="Loading spec..." />;
82
+ }
83
83
 
84
- return (
85
- <div className="space-y-4">
86
- {/* Spec Toolbar */}
87
- <div className="flex items-center justify-between">
88
- <div className="flex items-center gap-2">
89
- <Button variant="default" size="sm" onClick={handleSave}>
90
- Save
91
- </Button>
92
- <Button variant="outline" size="sm" onClick={handleValidate}>
93
- Validate
94
- </Button>
95
- {isDirty && (
96
- <Badge
97
- variant="secondary"
98
- className="border-amber-500/30 bg-amber-500/20 text-amber-400"
99
- >
100
- Unsaved changes
101
- </Badge>
102
- )}
103
- {validation && (
104
- <Badge
105
- variant={validation.valid ? 'default' : 'destructive'}
106
- className={
107
- validation.valid
108
- ? 'border-green-500/30 bg-green-500/20 text-green-400'
109
- : ''
110
- }
111
- >
112
- {validation.valid
113
- ? 'Valid'
114
- : `${validation.errors.filter((e) => e.severity === 'error').length} errors`}
115
- </Badge>
116
- )}
117
- </div>
118
- <div className="flex items-center gap-2">
119
- {lastSaved && (
120
- <span className="text-muted-foreground text-xs">
121
- Last saved: {new Date(lastSaved).toLocaleTimeString()}
122
- </span>
123
- )}
124
- <Button variant="ghost" size="sm" onPress={handleReset}>
125
- Reset
126
- </Button>
127
- </div>
128
- </div>
84
+ return (
85
+ <div className="space-y-4">
86
+ {/* Spec Toolbar */}
87
+ <div className="flex items-center justify-between">
88
+ <div className="flex items-center gap-2">
89
+ <Button variant="default" size="sm" onClick={handleSave}>
90
+ Save
91
+ </Button>
92
+ <Button variant="outline" size="sm" onClick={handleValidate}>
93
+ Validate
94
+ </Button>
95
+ {isDirty && (
96
+ <Badge
97
+ variant="secondary"
98
+ className="border-amber-500/30 bg-amber-500/20 text-amber-400"
99
+ >
100
+ Unsaved changes
101
+ </Badge>
102
+ )}
103
+ {validation && (
104
+ <Badge
105
+ variant={validation.valid ? 'default' : 'destructive'}
106
+ className={
107
+ validation.valid
108
+ ? 'border-green-500/30 bg-green-500/20 text-green-400'
109
+ : ''
110
+ }
111
+ >
112
+ {validation.valid
113
+ ? 'Valid'
114
+ : `${validation.errors.filter((e) => e.severity === 'error').length} errors`}
115
+ </Badge>
116
+ )}
117
+ </div>
118
+ <div className="flex items-center gap-2">
119
+ {lastSaved && (
120
+ <span className="text-muted-foreground text-xs">
121
+ Last saved: {new Date(lastSaved).toLocaleTimeString()}
122
+ </span>
123
+ )}
124
+ <Button variant="ghost" size="sm" onPress={handleReset}>
125
+ Reset
126
+ </Button>
127
+ </div>
128
+ </div>
129
129
 
130
- {/* Validation Errors */}
131
- {validation && validation.errors.length > 0 && (
132
- <div className="rounded-lg border border-amber-500/50 bg-amber-500/10 p-3">
133
- <p className="mb-2 text-xs font-semibold text-amber-400 uppercase">
134
- Validation Issues
135
- </p>
136
- <ul className="space-y-1">
137
- {validation.errors.map((error, index) => (
138
- <li
139
- key={`${error.line}-${error.message}-${index}`}
140
- className={`text-xs ${
141
- error.severity === 'error' ? 'text-red-400' : 'text-amber-400'
142
- }`}
143
- >
144
- Line {error.line}: {error.message}
145
- </li>
146
- ))}
147
- </ul>
148
- </div>
149
- )}
130
+ {/* Validation Errors */}
131
+ {validation && validation.errors.length > 0 && (
132
+ <div className="rounded-lg border border-amber-500/50 bg-amber-500/10 p-3">
133
+ <p className="mb-2 font-semibold text-amber-400 text-xs uppercase">
134
+ Validation Issues
135
+ </p>
136
+ <ul className="space-y-1">
137
+ {validation.errors.map((error, index) => (
138
+ <li
139
+ key={`${error.line}-${error.message}-${index}`}
140
+ className={`text-xs ${
141
+ error.severity === 'error' ? 'text-red-400' : 'text-amber-400'
142
+ }`}
143
+ >
144
+ Line {error.line}: {error.message}
145
+ </li>
146
+ ))}
147
+ </ul>
148
+ </div>
149
+ )}
150
150
 
151
- {/* Editor */}
152
- <div className="border-border bg-card rounded-2xl border p-4">
153
- <SpecEditor
154
- projectId="sandbox"
155
- type="CAPABILITY"
156
- content={content}
157
- onChange={setContent}
158
- metadata={{ template: templateId }}
159
- onSave={handleSave}
160
- onValidate={handleValidate}
161
- />
162
- </div>
163
- </div>
164
- );
151
+ {/* Editor */}
152
+ <div className="rounded-2xl border border-border bg-card p-4">
153
+ <SpecEditor
154
+ projectId="sandbox"
155
+ type="CAPABILITY"
156
+ content={content}
157
+ onChange={setContent}
158
+ metadata={{ template: templateId }}
159
+ onSave={handleSave}
160
+ onValidate={handleValidate}
161
+ />
162
+ </div>
163
+ </div>
164
+ );
165
165
  }
@@ -2,62 +2,62 @@ import type { ReactNode } from 'react';
2
2
 
3
3
  import { LocalDataIndicator } from './LocalDataIndicator';
4
4
  import {
5
- SaveToStudioButton,
6
- type SaveToStudioButtonProps,
5
+ SaveToStudioButton,
6
+ type SaveToStudioButtonProps,
7
7
  } from './SaveToStudioButton';
8
8
 
9
9
  export interface TemplateShellProps {
10
- title: string;
11
- description?: string;
12
- sidebar?: ReactNode;
13
- actions?: ReactNode;
14
- children: ReactNode;
15
- showSaveAction?: boolean;
16
- saveProps?: SaveToStudioButtonProps;
10
+ title: string;
11
+ description?: string;
12
+ sidebar?: ReactNode;
13
+ actions?: ReactNode;
14
+ children: ReactNode;
15
+ showSaveAction?: boolean;
16
+ saveProps?: SaveToStudioButtonProps;
17
17
  }
18
18
 
19
19
  export const TemplateShell = ({
20
- title,
21
- description,
22
- sidebar,
23
- actions,
24
- showSaveAction = true,
25
- saveProps,
26
- children,
20
+ title,
21
+ description,
22
+ sidebar,
23
+ actions,
24
+ showSaveAction = true,
25
+ saveProps,
26
+ children,
27
27
  }: TemplateShellProps) => (
28
- <div className="space-y-6">
29
- <header className="border-border bg-card rounded-2xl border p-6 shadow-sm">
30
- <div className="flex flex-wrap items-center justify-between gap-4">
31
- <div>
32
- <p className="text-muted-foreground text-sm font-semibold tracking-wide uppercase">
33
- ContractSpec Templates
34
- </p>
35
- <h1 className="text-3xl font-bold">{title}</h1>
36
- {description ? (
37
- <p className="text-muted-foreground mt-2 max-w-2xl text-sm">
38
- {description}
39
- </p>
40
- ) : null}
41
- </div>
42
- <div className="flex flex-col items-end gap-2">
43
- <LocalDataIndicator />
44
- {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
45
- </div>
46
- </div>
47
- {actions ? <div className="mt-4">{actions}</div> : null}
48
- </header>
28
+ <div className="space-y-6">
29
+ <header className="rounded-2xl border border-border bg-card p-6 shadow-sm">
30
+ <div className="flex flex-wrap items-center justify-between gap-4">
31
+ <div>
32
+ <p className="font-semibold text-muted-foreground text-sm uppercase tracking-wide">
33
+ ContractSpec Templates
34
+ </p>
35
+ <h1 className="font-bold text-3xl">{title}</h1>
36
+ {description ? (
37
+ <p className="mt-2 max-w-2xl text-muted-foreground text-sm">
38
+ {description}
39
+ </p>
40
+ ) : null}
41
+ </div>
42
+ <div className="flex flex-col items-end gap-2">
43
+ <LocalDataIndicator />
44
+ {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
45
+ </div>
46
+ </div>
47
+ {actions ? <div className="mt-4">{actions}</div> : null}
48
+ </header>
49
49
 
50
- <div
51
- className={
52
- sidebar ? 'grid gap-6 lg:grid-cols-[minmax(0,1fr)_320px]' : 'w-full'
53
- }
54
- >
55
- <main className="space-y-4 p-2">{children}</main>
56
- {sidebar ? (
57
- <aside className="border-border bg-card rounded-2xl border p-4">
58
- {sidebar}
59
- </aside>
60
- ) : null}
61
- </div>
62
- </div>
50
+ <div
51
+ className={
52
+ sidebar ? 'grid gap-6 lg:grid-cols-[minmax(0,1fr)_320px]' : 'w-full'
53
+ }
54
+ >
55
+ <main className="space-y-4 p-2">{children}</main>
56
+ {sidebar ? (
57
+ <aside className="rounded-2xl border border-border bg-card p-4">
58
+ {sidebar}
59
+ </aside>
60
+ ) : null}
61
+ </div>
62
+ </div>
63
63
  );