-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.js
More file actions
162 lines (153 loc) · 7.05 KB
/
config.js
File metadata and controls
162 lines (153 loc) · 7.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Central configuration — every user-editable knob lives here.
// All other modules derive from CONFIG; see README ▸ Configuration.
// Overrides: PUBLIC_SITE_URL, PUBLIC_SITE_BASE (env / Actions vars).
export const CONFIG = Object.freeze({
// Site identity
origin: "https://billmcilhargey.github.io",
base: "/m365-profiles",
name: "M365 Profiles",
tagline: "Microsoft 365 Licensing Decision Tree",
owner: "Dr. Bill Mcilhargey",
repo: "billmcilhargey/m365-profiles",
defaultBranch: "main",
// Brand colors — also mirrored in src/styles/tokens.css; keep in sync.
colors: Object.freeze({
blue: "#0078d4",
navy: "#003e72",
squares: Object.freeze(["#f25022", "#7fba00", "#00a4ef", "#ffb900"]),
}),
// Page metadata defaults
defaultDescription:
"Interactive decision tree that matches a Microsoft 365 identity profile to the right license tier — independent, unofficial community helper.",
language: "en",
direction: "ltr",
titleSeparator: " — ",
// Crawler / search-engine directives. Default opts into Google's largest
// rich-result image + unlimited snippet/video preview lengths. Per-page
// overrides go via <Base robots="noindex,nofollow" />.
seo: Object.freeze({
robots: "index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1",
// Whether to emit a <link rel="alternate" hreflang> self + x-default pair.
// Useful even for a single-language site; harmless otherwise.
emitHreflang: true,
// Whether to emit a BreadcrumbList JSON-LD block on non-home pages.
emitBreadcrumbs: true,
// Apple PWA status bar — "default" | "black" | "black-translucent".
appleStatusBarStyle: "default",
// Dark-mode <meta name="theme-color"> (light variant uses CONFIG.colors.blue).
themeColorDark: "#003e72",
}),
// Social / Open Graph / Twitter card metadata. All five "essential" tags
// from https://css-tricks.com/essential-meta-tags-social-media/ are emitted
// from these values; per-page overrides live in each page's frontmatter.
// OG images are generated at build time from CONFIG.colors + the per-page
// entry in `ogImages` below — no static binary assets required.
social: Object.freeze({
// OG locale uses the underscore form (e.g. "en_US"); language + region are
// recombined in Base.astro. Leave region empty to derive from language.
region: "US",
// Default og:type for pages that don't override (article, profile, etc.).
ogType: "website",
// Default OG image dimensions (the dynamic SVG endpoint matches these).
ogImageWidth: 1200,
ogImageHeight: 630,
// Default alt text — every page can override via Props.ogImageAlt.
ogImageAlt:
"M365 Profiles — Microsoft 365 licensing decision tree. Independent, unofficial community helper.",
// Optional analytics handles. Leave empty strings to omit the meta tags.
twitterSite: "", // e.g. "@yourhandle" → emits <meta name="twitter:site">
twitterCreator: "", // e.g. "@yourhandle" → emits <meta name="twitter:creator">
fbAppId: "", // e.g. "1234567890" → emits <meta property="fb:app_id">
// Owner profile URLs. Each becomes a <link rel="me"> in <head> (used by
// Mastodon / IndieWeb verification) and is folded into the JSON-LD
// Person.sameAs array (helps Google's Knowledge Graph). Leave empty to omit.
profiles: Object.freeze([
// "https://github.com/billmcilhargey",
// "https://www.linkedin.com/in/example/",
// "https://mastodon.social/@example",
]),
// Per-route OG image specs. Each key becomes /og/<key>.svg and is rendered
// at build time from CONFIG.colors using the headline + subline below.
// Keep entries short — the SVG generator wraps at ~24 chars per line.
ogImages: Object.freeze({
home: Object.freeze({
eyebrow: "Decision tree",
headline: "The right Microsoft 365 license for every profile.",
subline: "Step-by-step · Source-cited · PDF handout · No tracking",
}),
assessment: Object.freeze({
eyebrow: "Interactive assessment",
headline: "Find the right Microsoft 365 license.",
subline: "Eight profiles · 12 questions max · Citations on every screen",
}),
profiles: Object.freeze({
eyebrow: "Identity profiles",
headline: "Eight profiles, one decision tree.",
subline: "Admin · IW · Frontline · Edu · Gov · Nonprofit · SMB · Guest",
}),
reference: Object.freeze({
eyebrow: "Reference catalog",
headline: "Every recommendation, one page each.",
subline: "Static, citation-linked view of every result node",
}),
about: Object.freeze({
eyebrow: "About",
headline: "Methodology, sources & honest limits.",
subline: "Source-first · Cited · Not official Microsoft guidance",
}),
404: Object.freeze({
eyebrow: "404",
headline: "Page not found.",
subline: "The page you requested doesn't exist on this site.",
}),
}),
}),
// Web app manifest (/manifest.webmanifest)
manifest: Object.freeze({
description:
"Independent decision-tree helper that maps Microsoft 365 identity profiles to the right license tier.",
display: "minimal-ui",
orientation: "any",
backgroundColor: "#ffffff",
}),
// Security headers (delivered as <meta> tags; GitHub Pages can't set real headers)
security: Object.freeze({
csp: Object.freeze([
"default-src 'self'",
"script-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: blob:",
"font-src 'self' data:",
"connect-src 'self'",
"form-action 'none'",
"frame-ancestors 'none'",
"base-uri 'self'",
"object-src 'none'",
"upgrade-insecure-requests",
]),
referrerPolicy: "strict-origin-when-cross-origin",
permissionsPolicy: "camera=(), microphone=(), geolocation=(), interest-cohort=()",
}),
// Browser storage key prefixes. assessmentState is suffixed with APP_VERSION
// at runtime so each deploy invalidates in-progress sessions.
storage: Object.freeze({
theme: "m365-theme",
knownVersion: "m365-known-version",
assessmentStatePrefix: "m365-assessment-state",
}),
// Footer "source document" links. The first two are the legally binding
// sources of truth (Microsoft Licensing hub + Microsoft Product Terms,
// which contains the Use Rights for every Microsoft Online Service);
// the rest are operational / community references.
externalSources: Object.freeze([
{
href: "https://www.microsoft.com/licensing/terms",
label: "Microsoft Product Terms (Use Rights)",
},
{ href: "https://www.microsoft.com/en-us/licensing", label: "Microsoft Licensing Hub" },
{ href: "https://learn.microsoft.com/microsoft-365/", label: "Microsoft 365 Learn" },
{ href: "https://learn.microsoft.com/entra/", label: "Microsoft Entra Learn" },
{ href: "https://m365maps.com/", label: "M365 Maps (Aaron Dinnage)" },
{ href: "https://microsoft.github.io/zerotrustassessment/", label: "Zero Trust Assessment" },
]),
});