@gsa-tts/graymatter-ui 0.3.22 → 0.3.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsa-tts/graymatter-ui",
3
- "version": "0.3.22",
3
+ "version": "0.3.23",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,149 @@
1
+ <script lang="ts">
2
+ import { siteName } from '@gsa-tts/graymatter-ui/constants';
3
+ import { getUrlFromBase } from '@gsa-tts/graymatter-ui/helpers';
4
+ import Logo from '@gsa-tts/graymatter-ui/components/Logo.svelte';
5
+ import PlatformFooterMenu from './PlatformFooterMenu.svelte';
6
+ import Button from '@gsa-tts/graymatter-ui/components/Button.svelte';
7
+
8
+ /**
9
+ * PlatformFooter Component
10
+ *
11
+ * The main footer component for the platform, featuring:
12
+ * - Agency branding and logo
13
+ * - Call-to-action section
14
+ * - Footer navigation menus
15
+ *
16
+ * Props:
17
+ * - menus?: FooterMenu[] (optional array of footer menus)
18
+ * - ctaHeading?: string (optional CTA heading text)
19
+ * - ctaButtonText?: string (optional CTA button text)
20
+ * - ctaButtonHref?: string (optional CTA button URL)
21
+ * - showCta?: boolean (whether to show the CTA section)
22
+ * - class?: string (optional additional CSS classes)
23
+ *
24
+ * Example:
25
+ * ```svelte
26
+ * <PlatformFooter {menus} />
27
+ * ```
28
+ */
29
+ interface FooterLink {
30
+ title: string;
31
+ url: string;
32
+ }
33
+
34
+ interface FooterMenu {
35
+ title: string;
36
+ items: Array<FooterLink>;
37
+ }
38
+
39
+ interface Props {
40
+ menus?: FooterMenu[];
41
+ ctaHeading?: string;
42
+ ctaButtonText?: string;
43
+ ctaButtonHref?: string;
44
+ showCta?: boolean;
45
+ class?: string;
46
+ }
47
+
48
+ let {
49
+ menus = [],
50
+ ctaHeading = 'Get your team started today.',
51
+ ctaButtonText = 'Partnerships',
52
+ ctaButtonHref = getUrlFromBase('/partnerships'),
53
+ showCta = true,
54
+ class: className = '',
55
+ }: Props = $props();
56
+ </script>
57
+
58
+ <footer class="ai-footer {className}">
59
+ <div class="ai-maxw-widescreen grid-container">
60
+ {#if showCta}
61
+ <section
62
+ class="usa-section ai-section ai-footer-top"
63
+ aria-labelledby="ai-footer-cta"
64
+ >
65
+ <div
66
+ class="usa-identifier__identity ai-identifier__identity"
67
+ aria-label="Agency description"
68
+ >
69
+ <p
70
+ class="usa-identifier__identity-domain ai-identifier__identity-domain"
71
+ >
72
+ <a href={getUrlFromBase('/')} aria-label="Home">
73
+ <Logo
74
+ aria-label={siteName}
75
+ isInverted={true}
76
+ showServiceMark={true}
77
+ width={68}
78
+ />
79
+ </a>
80
+ </p>
81
+ <p class="usa-identifier__identity-disclaimer text-normal">
82
+ An official website of the U.S.
83
+ <a class="ai-footer-link" href="https://www.gsa.gov/"
84
+ >General Services Administration</a
85
+ >
86
+ </p>
87
+ </div>
88
+ <p class="ai-footer-cta__heading" id="ai-footer-cta">
89
+ {ctaHeading}
90
+ </p>
91
+ <div class="ai-footer-cta__buttons">
92
+ <Button href={ctaButtonHref} theme="inverted" variant="secondary">
93
+ {ctaButtonText}
94
+ </Button>
95
+ </div>
96
+ </section>
97
+ {/if}
98
+
99
+ {#if menus.length > 0}
100
+ <section class="usa-section ai-section">
101
+ <div class="grid-row grid-gap">
102
+ <div class="tablet:grid-col-12">
103
+ <nav aria-label="Footer navigation">
104
+ <div class="grid-row grid-gap">
105
+ {#each menus as menu}
106
+ <div class="tablet:grid-col-4">
107
+ <PlatformFooterMenu content={menu} />
108
+ </div>
109
+ {/each}
110
+ </div>
111
+ </nav>
112
+ </div>
113
+ </div>
114
+ </section>
115
+ {/if}
116
+ </div>
117
+ </footer>
118
+
119
+ <style>
120
+ .ai-footer-link {
121
+ color: var(--ai-footer-color-link-rest);
122
+ }
123
+
124
+ .ai-footer-link:hover {
125
+ color: var(--ai-footer-color-link-hover);
126
+ }
127
+
128
+ .ai-footer {
129
+ background: var(--ai-footer-color-background);
130
+ color: var(--ai-footer-color-text);
131
+ }
132
+
133
+ .ai-footer-cta__heading {
134
+ margin-block: 0 var(--ai-size-24);
135
+ }
136
+
137
+ .ai-footer-top {
138
+ border-bottom: 1px solid var(--ai-footer-color-separator);
139
+ }
140
+
141
+ .ai-identifier__identity {
142
+ padding-bottom: var(--ai-layout-section-spacing-y);
143
+ }
144
+
145
+ .ai-identifier__identity-domain {
146
+ color: var(--ai-footer-color-text);
147
+ font-weight: 600;
148
+ }
149
+ </style>
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import { v4 as uuidv4 } from 'uuid';
3
+
4
+ /**
5
+ * PlatformFooterMenu Component
6
+ *
7
+ * A footer menu component that displays a title and list of links.
8
+ * Used within the PlatformFooter component to create organized footer navigation.
9
+ *
10
+ * Props:
11
+ * - content: FooterMenu object containing title and items
12
+ * - class?: string (optional additional CSS classes)
13
+ *
14
+ * Example:
15
+ * ```svelte
16
+ * <PlatformFooterMenu content={menuData} />
17
+ * ```
18
+ */
19
+ interface FooterLink {
20
+ title: string;
21
+ url: string;
22
+ }
23
+
24
+ interface FooterMenu {
25
+ title: string;
26
+ items: Array<FooterLink>;
27
+ }
28
+
29
+ interface Props {
30
+ content: FooterMenu;
31
+ class?: string;
32
+ }
33
+
34
+ let { content, class: className = '' }: Props = $props();
35
+
36
+ // Generate unique ID for accessibility
37
+ const menuLabel = `platform-footer-${uuidv4()}`;
38
+ </script>
39
+
40
+ <div class={className}>
41
+ <p id={menuLabel}>{content.title}</p>
42
+ <ul class="add-list-reset" aria-labelledby={menuLabel}>
43
+ {#each content.items as item}
44
+ <li>
45
+ <a href={item.url}>{item.title}</a>
46
+ </li>
47
+ {/each}
48
+ </ul>
49
+ </div>
50
+
51
+ <style>
52
+ p {
53
+ color: var(--ai-footer-color-text-muted);
54
+ margin-top: 0;
55
+ margin-bottom: var(--ai-size-16);
56
+ }
57
+
58
+ ul {
59
+ margin-bottom: var(--ai-size-32);
60
+ }
61
+
62
+ li {
63
+ display: block;
64
+ margin-bottom: var(--ai-size-16);
65
+ }
66
+
67
+ a {
68
+ color: var(--ai-footer-color-link-rest);
69
+ display: block;
70
+ text-decoration: none;
71
+ }
72
+
73
+ a:hover {
74
+ color: var(--ai-footer-color-link-hover);
75
+ }
76
+
77
+ a:is(:focus, :hover, :active) {
78
+ text-decoration: underline;
79
+ }
80
+ </style>
@@ -12,6 +12,8 @@ export { default as UsaSkipNav } from './UsaSkipNav.svelte';
12
12
  export { default as ApiDocSubNavMenu } from './ApiDocSubNavMenu.svelte';
13
13
  export { default as ApiDocSubNavList } from './ApiDocSubNavList.svelte';
14
14
  export { default as ApiDocSubNavMenuItem } from './ApiDocSubNavMenuItem.svelte';
15
+ export { default as PlatformFooter } from './PlatformFooter.svelte';
16
+ export { default as PlatformFooterMenu } from './PlatformFooterMenu.svelte';
15
17
 
16
18
  // Icon Components
17
19
  export * from './icons/index.js';