diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index fd82da51..a9ac9250 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,7 +2,7 @@ ## Project Overview -This is the **Decap CMS website** built with **Hugo 0.148.1**. The site was successfully migrated from Gatsby in October 2025. +This is the **Decap CMS website** built with **Hugo**. The site was successfully migrated from Gatsby in October 2025. - **Production**: Hugo implementation (root directory) - **Legacy**: Gatsby source code (`gatsby/`) - kept for reference only, not actively maintained @@ -187,7 +187,7 @@ hugo --gc --minify # Build optimized site - **File**: `netlify.toml` in root - **Build command**: `hugo --gc --minify` - **Publish directory**: `public` -- **Hugo version**: 0.148.1 (extended) +- **Hugo version**: 0.155.3 (extended) ## Migration Patterns diff --git a/assets/scripts/vulnerability-form.js b/assets/scripts/vulnerability-form.js new file mode 100644 index 00000000..2780f2a0 --- /dev/null +++ b/assets/scripts/vulnerability-form.js @@ -0,0 +1,45 @@ +/** + * Vulnerability Report Form Handler + */ + +const form = document.getElementById('vulnerability-form') + +function handleVulnerabilityFormSubmit (event) { + event.preventDefault() + + const submitButton = document.getElementById('submit-button') + const errorMessage = document.getElementById('error-message') + const errorText = document.getElementById('error-text') + const successMessage = document.getElementById('success-message') + + errorMessage.classList.add('is-hidden') + successMessage.classList.add('is-hidden') + + submitButton.disabled = true + + const formData = new FormData(form) + + fetch('/', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams(formData).toString(), + }) + .then((res) => { + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`) + } + submitButton.disabled = false + form.classList.add('is-hidden') + successMessage.classList.remove('is-hidden') + successMessage.scrollIntoView({ behavior: 'smooth', block: 'start' }) + }) + .catch((error) => { + console.error('Form submission error:', error) + errorText.textContent = 'Error submitting report. Please try again or contact us directly if the problem persists.' + errorMessage.classList.remove('is-hidden') + submitButton.disabled = false + errorMessage.scrollIntoView({ behavior: 'smooth', block: 'start' }) + }) +} + +form?.addEventListener('submit', handleVulnerabilityFormSubmit) diff --git a/assets/styles/_base.scss b/assets/styles/_base.scss index fbb517b2..1c4c97df 100644 --- a/assets/styles/_base.scss +++ b/assets/styles/_base.scss @@ -19,4 +19,8 @@ img { iframe { width: 100%; +} + +.is-hidden { + display: none !important; } \ No newline at end of file diff --git a/assets/styles/_forms.scss b/assets/styles/_forms.scss new file mode 100644 index 00000000..68720e85 --- /dev/null +++ b/assets/styles/_forms.scss @@ -0,0 +1,107 @@ +// Generic form element styles + +form { + display: flex; + flex-direction: column; + margin-bottom: var(--space-6); +} + +input[type="text"], +input[type="email"], +input[type="password"], +textarea { + padding: var(--space-2) var(--space-3); + font-size: var(--font-size-md); + font-family: var(--font-family-primary); + border: 1px solid var(--color-lightest-gray); + border-radius: var(--radius-md); + background-color: var(--color-white); + + &:focus { + outline: none; + border-color: var(--color-blue); + box-shadow: 0 0 0 2px rgba(58, 105, 199, 0.1); + } +} + +textarea { + resize: vertical; + min-height: 100px; +} + +input[type="checkbox"] { + + margin: 0; + width: 16px; + height: 16px; +} + +.form-element { + display: flex; + flex-direction: column; + gap: var(--space-2); + margin-bottom: var(--space-4); + + span { + font-weight: var(--font-weight-medium); + font-size: var(--font-size-md); + } + + &:has(input:required, textarea:required) { + span:after { + content: ' *'; + color: var(--color-primary-light); + } + } + + small { + font-size: var(--font-size-sm); + color: var(--color-lightish-gray); + } + + &--checkbox { + label { + display: flex; + gap: var(--space-2); + align-items: center; + } + } +} + +button[type="submit"] { + align-self: flex-start; +} + +// Message containers +.form-success, +.form-error { + padding: var(--space-3) var(--space-4); + border-radius: var(--radius-md); + margin: var(--space-4) 0; +} + +.form-success { + background-color: #e8f5e9; + border-left: 4px solid #388e3c; + color: #1b5e20; + + h3 { + margin-top: 0; + color: #1b5e20; + } + + p { + margin: var(--space-2) 0; + color: #2e7d32; + } +} + +.form-error { + background-color: #fce4ec; + border-left: 4px solid #d32f2f; + color: #c62828; + + p { + margin: 0; + } +} diff --git a/assets/styles/components/_button.scss b/assets/styles/components/_button.scss index 7127e53c..96cb75e0 100644 --- a/assets/styles/components/_button.scss +++ b/assets/styles/components/_button.scss @@ -52,4 +52,12 @@ background: var(--color-primary-light); border-color: var(--color-primary-light); } + + &[disabled] { + background-color: var(--color-light-gray); + border-color: var(--color-light-gray); + color: var(--color-gray); + cursor: not-allowed; + opacity: 0.7; + } } diff --git a/assets/styles/components/_page-hero.scss b/assets/styles/components/_page-hero.scss new file mode 100644 index 00000000..7b4010e9 --- /dev/null +++ b/assets/styles/components/_page-hero.scss @@ -0,0 +1,3 @@ +.page-hero { + margin-bottom: var(--space-6); +} \ No newline at end of file diff --git a/assets/styles/components/_search.scss b/assets/styles/components/_search.scss index a1979e11..e1273927 100644 --- a/assets/styles/components/_search.scss +++ b/assets/styles/components/_search.scss @@ -3,6 +3,7 @@ &__form { width: 100%; + margin: 0; } &__field { diff --git a/assets/styles/layouts/_community.scss b/assets/styles/layouts/_community.scss index 043f9cbb..4291ba71 100644 --- a/assets/styles/layouts/_community.scss +++ b/assets/styles/layouts/_community.scss @@ -1,7 +1,3 @@ -.community-header { - margin-bottom: var(--space-6); -} - .community-section { margin-bottom: var(--space-6); } diff --git a/assets/styles/style.scss b/assets/styles/style.scss index b65a1b6b..9fd6b0fc 100644 --- a/assets/styles/style.scss +++ b/assets/styles/style.scss @@ -13,6 +13,7 @@ @import 'table'; @import 'header'; @import 'footer'; +@import 'forms'; @import 'layouts/page'; @import 'layouts/blog-list'; @@ -24,9 +25,11 @@ @import 'components/search'; @import 'components/alert'; @import 'components/template-card'; + @import 'components/button'; @import 'components/container'; @import 'components/hero-title'; +@import 'components/page-hero'; @import 'components/pagination-nav'; @import 'components/version-tag'; @import 'components/page-layout'; diff --git a/content/community.md b/content/community.md index 3de30235..6deca3ee 100644 --- a/content/community.md +++ b/content/community.md @@ -1,8 +1,8 @@ --- -title: Community +linkTitle: Community layout: community -headline: Help us build the CMS of the future. -subhead: Get help, help others, and find out what's new through the channels below. +title: Help us build the CMS of the future. +description: Get help, help others, and find out what's new through the channels below. sections: - title: Contributing channels: diff --git a/content/report-vulnerability.md b/content/report-vulnerability.md new file mode 100644 index 00000000..8c07e61e --- /dev/null +++ b/content/report-vulnerability.md @@ -0,0 +1,44 @@ +--- +title: Report a Security Vulnerability +description: You can confidentially report security vulnerabilities in Decap CMS by filling out this form. Do not open public GitHub issues for security vulnerabilities! +layout: report-vulnerability +success_title: Thank You for Your Report +success_message: We've received your vulnerability submission. We'll investigate it and work with you to understand the problem. If confirmed, we'll coordinate a fix and responsible disclosure with you. +button_text: Submit Vulnerability Report +form_fields: + title: + label: Vulnerability Title + placeholder: e.g., XSS vulnerability in markdown widget + help: Brief summary of the security issue (max 200 characters) + maxlength: 200 + description: + label: Detailed Description + placeholder: Describe what the vulnerability is and why it's a security concern... + help: Explain the vulnerability in detail, including how it occurs (10-5000 characters) + minlength: 10 + maxlength: 5000 + versions: + label: Affected Version(s) + placeholder: e.g., 3.0.0, 3.1.x + help: Which version(s) of Decap CMS are affected? + steps: + label: Steps to Reproduce + placeholder: "1. Start Decap CMS with...\n2. Navigate to...\n3. Observe..." + help: Clear, numbered steps to demonstrate the vulnerability (optional, max 3000 characters) + maxlength: 3000 + impact: + label: Potential Impact + placeholder: This vulnerability could allow attackers to... + help: What is the impact of this vulnerability? (e.g., data exposure, unauthorized access, content integrity) + maxlength: 2000 + name: + label: Your Name + maxlength: 100 + email: + label: Your Email + placeholder: your@email.com + help: We'll use this to acknowledge receipt and follow up with you. We won't share it without your consent. + credit: + label: I would like public credit for this report + help: Your name will appear in the GitHub Security Advisory and release notes (unless you provide alternate details) +--- diff --git a/layouts/_default/community.html b/layouts/_default/community.html index c7c547b1..bd67f773 100644 --- a/layouts/_default/community.html +++ b/layouts/_default/community.html @@ -1,10 +1,7 @@ {{ define "main" }}
-
-

{{ .Params.headline | markdownify }}

-

{{ .Params.subhead | markdownify }}

-
+ {{ partial "page-hero" . }} {{ range .Params.sections }}
diff --git a/layouts/_default/report-vulnerability.html b/layouts/_default/report-vulnerability.html new file mode 100644 index 00000000..41dccfaf --- /dev/null +++ b/layouts/_default/report-vulnerability.html @@ -0,0 +1,20 @@ +{{ define "main" }} +
+
+ {{ partial "page-hero" . }} + + {{ partial "vulnerability-report-form" . }} + + {{ with .Content }} +
+ {{ . }} +
+ {{ end }} +
+
+{{ end }} + +{{ define "scripts" }} + {{ $formJS := resources.Get "/scripts/vulnerability-form.js" | js.Build (dict "minify" true) }} + +{{ end }} diff --git a/layouts/features/single.html b/layouts/features/single.html index 4c06aecc..7904a493 100644 --- a/layouts/features/single.html +++ b/layouts/features/single.html @@ -1,11 +1,7 @@ {{ define "main" }}
-

{{ .Title }}

- - {{ if .Params.description }} -

{{ .Params.description }}

- {{ end }} + {{ partial "page-hero" . }} {{ if .Content }}
diff --git a/layouts/partials/page-hero.html b/layouts/partials/page-hero.html new file mode 100644 index 00000000..e69a3a45 --- /dev/null +++ b/layouts/partials/page-hero.html @@ -0,0 +1,7 @@ +
+

{{ .Title }}

+ + {{ with .Description }} +

{{ . }}

+ {{ end }} +
\ No newline at end of file diff --git a/layouts/partials/vulnerability-report-form.html b/layouts/partials/vulnerability-report-form.html new file mode 100644 index 00000000..c33597d1 --- /dev/null +++ b/layouts/partials/vulnerability-report-form.html @@ -0,0 +1,129 @@ +
+ + + {{ with .Params.form_fields.title }} + + {{ end }} + + {{ with .Params.form_fields.description }} + + {{ end }} + + {{ with .Params.form_fields.versions }} + + {{ end }} + + {{ with .Params.form_fields.steps }} + + {{ end }} + + {{ with .Params.form_fields.impact }} + + {{ end }} + + {{ with .Params.form_fields.name }} + + {{ end }} + + {{ with .Params.form_fields.email }} + + {{ end }} + + {{ with .Params.form_fields.credit }} +
+ + {{ .help }} +
+ {{ end }} + + + + +
+ + diff --git a/netlify.toml b/netlify.toml index 52db9cfd..27faa525 100644 --- a/netlify.toml +++ b/netlify.toml @@ -3,7 +3,7 @@ command = "hugo --gc --minify" [build.environment] - HUGO_VERSION = "0.148.1" + HUGO_VERSION = "0.155.3" HUGO_ENV = "production" HUGO_ENABLEGITINFO = "true" diff --git a/static/admin/config.yml b/static/admin/config.yml index 1a509c94..4623c66d 100644 --- a/static/admin/config.yml +++ b/static/admin/config.yml @@ -161,9 +161,9 @@ collections: file: content/community.md preview_path: community fields: + - { label: Link Title, name: linkTitle } - { label: Title, name: title } - - { label: Headline, name: headline } - - { label: Subheading, name: subhead } + - { label: Description, name: description } - label: Sections name: sections widget: list