From d57cadc4e3f2bf85a71664a818f660994894bf4e Mon Sep 17 00:00:00 2001 From: Jazzy Gasper Date: Tue, 8 Oct 2024 16:24:37 -0700 Subject: [PATCH 1/5] fix: add border on search input field on home page hero so that input is more visible on safari mobile --- client/src/homepage/homepage-hero/index.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/homepage/homepage-hero/index.scss b/client/src/homepage/homepage-hero/index.scss index 7ba3d366d47d..623bb7b23379 100644 --- a/client/src/homepage/homepage-hero/index.scss +++ b/client/src/homepage/homepage-hero/index.scss @@ -87,6 +87,7 @@ .search-input-field { background-color: rgba(1, 1, 1, 0.5); + border-color: var(--border-primary); border-radius: 10rem; padding: 2rem; width: 100%; From ee6c0922a186729eef873f21eadee6560da7fde9 Mon Sep 17 00:00:00 2001 From: Onkar Khadangale <87750369+OnkarRuikar@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:57:59 +0530 Subject: [PATCH 2/5] fix(layout): avoid sticky header gap (#11644) Co-authored-by: Claas Augner <495429+caugner@users.noreply.github.com> --- client/src/app.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/app.scss b/client/src/app.scss index f0e38641c4cf..eb5427c31dbf 100644 --- a/client/src/app.scss +++ b/client/src/app.scss @@ -355,7 +355,8 @@ sup.new { .sticky-header-container { position: sticky; - top: 0; + // Avoid gap on certain zoom levels. + top: -1px; z-index: var(--z-index-main-header); } From c3cdab20aae41ac05b926ce6567b6dd5ce1af3a0 Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Fri, 6 Dec 2024 13:57:15 +0000 Subject: [PATCH 3/5] chore: move copy to external generic-content repo (#12068) https://mozilla-hub.atlassian.net/browse/MP-1627 --- .env-dist | 1 + .github/workflows/prod-build.yml | 7 + .github/workflows/stage-build.yml | 8 +- .github/workflows/test-build.yml | 8 +- build/spas.ts | 38 +++--- copy/community/community.md | 160 ---------------------- copy/config.json | 29 ---- copy/observatory/faq.md | 183 ------------------------- copy/observatory/tests_and_scoring.md | 60 -------- copy/plus/faq.md | 103 -------------- copy/plus/features/ai-help.md | 89 ------------ copy/plus/features/collections.md | 190 -------------------------- copy/plus/features/offline.md | 60 -------- copy/plus/features/overview.md | 16 --- copy/plus/features/playground.md | 72 ---------- copy/plus/features/updates.md | 83 ----------- docs/envvars.md | 6 + libs/env/index.d.ts | 1 + libs/env/index.js | 4 + 19 files changed, 51 insertions(+), 1067 deletions(-) delete mode 100644 copy/community/community.md delete mode 100644 copy/config.json delete mode 100644 copy/observatory/faq.md delete mode 100644 copy/observatory/tests_and_scoring.md delete mode 100644 copy/plus/faq.md delete mode 100644 copy/plus/features/ai-help.md delete mode 100644 copy/plus/features/collections.md delete mode 100644 copy/plus/features/offline.md delete mode 100644 copy/plus/features/overview.md delete mode 100644 copy/plus/features/playground.md delete mode 100644 copy/plus/features/updates.md diff --git a/.env-dist b/.env-dist index fde17baddea9..bcb00ecc0760 100644 --- a/.env-dist +++ b/.env-dist @@ -1,6 +1,7 @@ CONTENT_ROOT=../content/files #CONTENT_TRANSLATED_ROOT=../translated-content/files #CONTRIBUTOR_SPOTLIGHT_ROOT=../mdn-contributor-spotlight/contributors +#GENERIC_CONTENT_ROOT=../generic-content/files REACT_APP_DEV_MODE=true diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml index 676efa7af157..99d983398106 100644 --- a/.github/workflows/prod-build.yml +++ b/.github/workflows/prod-build.yml @@ -89,6 +89,12 @@ jobs: lfs: true token: ${{ secrets.MDN_STUDIO_PAT }} + - uses: actions/checkout@v4 + if: ${{ ! vars.SKIP_BUILD }} + with: + repository: mdn/generic-content + path: mdn/generic-content + - uses: actions/checkout@v4 if: ${{ ! vars.SKIP_BUILD }} with: @@ -189,6 +195,7 @@ jobs: CONTRIBUTOR_SPOTLIGHT_ROOT: ${{ github.workspace }}/mdn/mdn-contributor-spotlight/contributors BLOG_ROOT: ${{ github.workspace }}/mdn/mdn-studio/content/posts CURRICULUM_ROOT: ${{ github.workspace }}/mdn/curriculum + GENERIC_CONTENT_ROOT: ${{ github.workspace }}/mdn/generic-content/files BASE_URL: "https://developer.mozilla.org" # The default for this environment variable is geared for writers diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml index e177747a9047..ce8d912a774e 100644 --- a/.github/workflows/stage-build.yml +++ b/.github/workflows/stage-build.yml @@ -124,6 +124,12 @@ jobs: lfs: true token: ${{ secrets.MDN_STUDIO_PAT }} + - uses: actions/checkout@v4 + if: ${{ ! vars.SKIP_BUILD }} + with: + repository: mdn/generic-content + path: mdn/generic-content + - uses: actions/checkout@v4 if: ${{ ! vars.SKIP_BUILD }} with: @@ -220,11 +226,11 @@ jobs: CONTRIBUTOR_SPOTLIGHT_ROOT: ${{ github.workspace }}/mdn/mdn-contributor-spotlight/contributors BLOG_ROOT: ${{ github.workspace }}/mdn/mdn-studio/content/posts CURRICULUM_ROOT: ${{ github.workspace }}/mdn/curriculum + GENERIC_CONTENT_ROOT: ${{ github.workspace }}/mdn/generic-content/files BASE_URL: "https://developer.allizom.org" # rari BUILD_OUT_ROOT: "client/build" - GENERIC_CONTENT_ROOT: "copy" LIVE_SAMPLES_BASE_URL: https://live.mdnyalp.dev INTERACTIVE_EXAMPLES_BASE_URL: https://interactive-examples.mdn.allizom.net ADDITIONAL_LOCALES_FOR_GENERICS_AND_SPAS: de diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index be04b8677820..68aed969c984 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -58,6 +58,12 @@ jobs: lfs: true token: ${{ secrets.MDN_STUDIO_PAT }} + - uses: actions/checkout@v4 + if: ${{ ! vars.SKIP_BUILD }} + with: + repository: mdn/generic-content + path: mdn/generic-content + - uses: actions/checkout@v4 if: ${{ ! vars.SKIP_BUILD }} with: @@ -130,11 +136,11 @@ jobs: CONTRIBUTOR_SPOTLIGHT_ROOT: ${{ github.workspace }}/mdn/mdn-contributor-spotlight/contributors BLOG_ROOT: ${{ github.workspace }}/mdn/mdn-studio/content/posts CURRICULUM_ROOT: ${{ github.workspace }}/mdn/curriculum + GENERIC_CONTENT_ROOT: ${{ github.workspace }}/mdn/generic-content/files BASE_URL: "https://test.developer.allizom.org" # rari BUILD_OUT_ROOT: "client/build" - GENERIC_CONTENT_ROOT: "copy" LIVE_SAMPLES_BASE_URL: https://live.test.mdnyalp.dev INTERACTIVE_EXAMPLES_BASE_URL: https://interactive-examples.mdn.allizom.net ADDITIONAL_LOCALES_FOR_GENERICS_AND_SPAS: de diff --git a/build/spas.ts b/build/spas.ts index b7440fc41f6f..62e52645f654 100644 --- a/build/spas.ts +++ b/build/spas.ts @@ -1,6 +1,5 @@ import fs from "node:fs"; import path from "node:path"; -import { fileURLToPath } from "node:url"; import frontmatter from "front-matter"; import { fdir, PathsOutput } from "fdir"; @@ -22,6 +21,7 @@ import { CONTRIBUTOR_SPOTLIGHT_ROOT, BUILD_OUT_ROOT, DEV_MODE, + GENERIC_CONTENT_ROOT, } from "../libs/env/index.js"; import { isValidLocale } from "../libs/locale-utils/index.js"; import { DocFrontmatter, DocParent, NewsItem } from "../libs/types/document.js"; @@ -271,7 +271,7 @@ export async function buildSPAs(options: { async function buildStaticPages( dirpath: string, slugPrefix?: string, - title = "MDN" + title?: string ) { const crawler = new fdir() .withFullPaths() @@ -282,7 +282,7 @@ export async function buildSPAs(options: { for (const filepath of filepaths) { const file = filepath.replace(dirpath, ""); - const page = file.split(".")[0]; + const page = file.split(".")[0].slice(1); const locale = DEFAULT_LOCALE; const pathLocale = locale.toLowerCase(); @@ -320,9 +320,9 @@ export async function buildSPAs(options: { }; const context: HydrationData = { hyData, - pageTitle: frontMatter.attributes.title + pageTitle: title ? `${frontMatter.attributes.title} | ${title}` - : title, + : frontMatter.attributes.title, url, }; @@ -343,21 +343,19 @@ export async function buildSPAs(options: { } } - await buildStaticPages( - fileURLToPath(new URL("../copy/plus/", import.meta.url)), - "plus/docs", - "MDN Plus" - ); - await buildStaticPages( - fileURLToPath(new URL("../copy/observatory/", import.meta.url)), - "observatory/docs", - OBSERVATORY_TITLE - ); - await buildStaticPages( - fileURLToPath(new URL("../copy/community/", import.meta.url)), - "", - "Contribute to MDN" - ); + if (GENERIC_CONTENT_ROOT) { + await buildStaticPages( + path.join(GENERIC_CONTENT_ROOT, "plus"), + "plus/docs", + "MDN Plus" + ); + await buildStaticPages( + path.join(GENERIC_CONTENT_ROOT, "observatory"), + "observatory/docs", + OBSERVATORY_TITLE + ); + await buildStaticPages(path.join(GENERIC_CONTENT_ROOT, "community")); + } // Build all the home pages in all locales. // Fetch merged content PRs for the latest contribution section. diff --git a/copy/community/community.md b/copy/community/community.md deleted file mode 100644 index a0f35e196761..000000000000 --- a/copy/community/community.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: Contribute to MDN ---- - -# MDN Community - -Where web enthusiasts learn, collaborate, and create - -- [Start contributing](#join_us_in_shaping_a_better_web) -- [Join MDN Discord](https://mdn.dev/discord) - - - -- **45K+** Total contributors -- **200+** Weekly commits -- **7** Language communities - -## MDN's community powers the web - -MDN’s strength comes from the passion and dedication of our global community. -Since our founding in 2005, we’ve grown into a thriving network. Together, we’ve -created a comprehensive, open, and free resource that serves web developers -across the globe. With volunteers leading translation efforts in -[7 languages](/en-US/docs/MDN/Community/Contributing/Translated_content), we’re -truly international. - -## Meet our contributors - -We are an open-source community dedicated to building resources for a better -web. Our diverse contributors, including developers, technical writers, -students, educators, designers, and more, come from various backgrounds and -platforms. Anyone can contribute, and each contribution strengthens our -community, driving innovation and improving this vital resource for developers -worldwide. - -- [Join us](/en-US/docs/MDN/Community/Contributing/Getting_started) -- [View all contributors](https://github.com/mdn/content/graphs/contributors) - - - -- Jason Lam, 林家祥 https://github.com/JasonLamv-t Grantit -- Nicolò Ribaudo https://github.com/nicolo-ribaudo Igalia -- Joshua Chen https://github.com/Josh-Cena -- Kimchanmin https://github.com/c17an SK Planet -- Gibbeum Yoon https://github.com/givvemee -- Jongha Kim https://github.com/wisedog -- Qizhe ZHANG https://github.com/PassionPenguin -- Artem Shibakov https://github.com/saionaro Bright Data -- HoChan Lee https://github.com/hochan222 11STREET -- Sangchul Lee https://github.com/1ilsang WoowaBros -- Park Sunhee https://github.com/sunhpark42 WoowaBros -- FU CHUNHUI https://github.com/fuchunhui Baidu -- Estelle Weyl https://github.com/estelle Open Web Docs -- Yitao Yin https://github.com/yin1999 Northwestern Polytechnical University -- Florian Scholz https://github.com/Elchi3 Open Web Docs - - - -## Contributor spotlight - -- > There are many other things I like about MDN: the openness of its - > governance, the respect for contributors' work, the professional - > conversations, and the always timely reviews. MDN has consistently - > demonstrated the ideal form of an open-source project. - - [Joshua Chen](/en-US/community/spotlight/joshua-chen) (MDN contributor) - -- > MDN Web Docs has the most up-to-date and accurate information and the - > content is presented in an easy-to-understand manner. I also like that it's - > available in many languages (very important!). - - [Yuji](/en-US/community/spotlight/yuji) (MDN contributor) - -- > There are millions of web developers in China, and many of them begin their - > developer journey at MDN Web Docs. Contributing to MDN Web Docs is an - > excellent way to help people who are starting out. - - [YiTao Yin](/en-US/community/spotlight/yitao-yin) (MDN contributor) - -If you wish to be a part of the featured contributors here, -[let us know](https://forms.gle/7yk13Nn1WRLnuLvy5).
If you’re featured here -and would like to opt-out, -[please file an issue on GitHub](https://github.com/mdn/content/issues/new?assignees=&labels=needs+triage&projects=&template=content-bug.yml). - -## Learn how to get started - -We collaborate on [GitHub](https://github.com/mdn), our project's home, on -various tasks such as writing and improving documentation, fixing bugs, and -providing review feedback. It starts here, with you. Want to start right away, -but not sure how? Follow -[our guide](https://github.com/mdn/content/blob/main/CONTRIBUTING.md#mdn-web-docs-contribution-guide) -to make your first contribution. - -Watch this video on -[how to get started with contributing to MDN](https://www.youtube.com/watch?v=Xnhnu7PViQE). - -[Video from the community team on contributing to MDN](https://www.youtube.com/watch?v=Xnhnu7PViQE) - -## Join us in shaping a better web - -Become part of this globally cherished group that’s dedicated to documenting web -technologies. Whether you’re an expert or a beginner, there’s a place for you in -our inclusive community. Check out some of the ways you can contribute and -engage. - -- ### Fix issues - - Submit pull requests to fix reported issues. - - [Squash bugs](https://github.com/mdn/content/issues) - -- ### Improve content - - Fix inaccuracies and fill in missing information. - - [Start writing](https://github.com/mdn/content/#readme) - -- ### Localize content - - Participate in translating content into one of our supported languages. - - [Find your locale](/en-US/docs/MDN/Community/Contributing/Translated_content#active_locales) - -- ### Answer questions - - Share your knowledge and expertise and guide fellow learners. - - [Help on Discord](https://mdn.dev/discord) - -## Help us fix open issues - -New to MDN or open-source projects? Tackle our beginner-friendly issues to help -improve MDN. - -## Join the conversation - -- ### Chat with us on Discord - - Connect with the community. Engage with domain experts. Help others learn. - - [Join MDN Discord](https://mdn.dev/discord) - -- ### Join our Community Call - - Every month, get exclusive updates from the MDN team. Share your ideas and - contributions. - - [RSVP to the next community call](https://github.com/mdn/community-meetings?tab=readme-ov-file#mdn-community-meetings) - -While working in Mozilla spaces and communities, please adhere to the -[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/), -which promote respect, inclusion, and a harassment-free environment for all -community members. - -## Licensing and reuse - -MDN's resources are freely available under various open-source licenses. For -detailed information on reusing MDN content, check out our -[Attribution and Copyright Licensing](https://developer.mozilla.org/en-US/docs/MDN/About#using_mdn_web_docs_content) -page. diff --git a/copy/config.json b/copy/config.json deleted file mode 100644 index 6438b35bbbc1..000000000000 --- a/copy/config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "pages": { - "community": { - "titleSuffix": "Contribute to MDN" - }, - "plus": { - "slugPrefix": "plus/docs", - "titleSuffix": "MDN Plus" - }, - "observatory": { - "slugPrefix": "observatory/docs", - "titleSuffix": "HTTP Observatory" - } - }, - "spas": { - "about": { - "slug": "about", - "pageTitle": "About MDN" - }, - "advertising": { - "slug": "advertising", - "pageTitle": "Advertise with us" - }, - "plus": { - "slug": "plus", - "pageTitle": "MDN Plus" - } - } -} diff --git a/copy/observatory/faq.md b/copy/observatory/faq.md deleted file mode 100644 index be1491e5c6e4..000000000000 --- a/copy/observatory/faq.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -title: FAQ ---- - -# Frequently asked questions - -## Should I implement all recommendations? - -Yes, you should do it if possible. There is no way to programmatically determine -the risk level of any given site. However, while your site may not be high-risk, -it is still worth learning about the defensive security standards highlighted by -Observatory, and implementing them wherever you can. - -## If I get an A+ grade, does that mean my site is secure? - -We'd love to say that any site that gets an A+ Observatory grade is perfectly -secure, but there are a lot of security considerations that we can't test. -Observatory tests for preventative measures against -[Cross-site scripting (XSS)](/en-US/docs/Glossary/Cross-site_scripting) attacks, -[manipulator-in-the-middle (MiTM)](/en-US/docs/Glossary/MitM) attacks, -cross-domain information leakage, insecure -[cookies](/en-US/docs/Web/HTTP/Cookies), -[Content Delivery Network](/en-US/docs/Glossary/CDN) (CDN) compromises, and -improperly issued certificates. - -However, it does not test for outdated software versions, -[SQL injection](/en-US/docs/Glossary/SQL_Injection) vulnerabilities, vulnerable -content management system plugins, improper creation or storage of passwords, -and more. These are just as important as the issues Observatory _does_ test for, -and site operators should not be neglectful of them simply because they score -well on Observatory. - -## Can I scan non-websites, such as API endpoints? - -The HTTP Observatory is designed for scanning websites, not API endpoints. It -can be used for API endpoints, and the security headers expected by Observatory -shouldn't cause any negative impact for APIs that return exclusively data, such -as JSON or XML. However, the results may not accurately reflect the security -posture of the API. API endpoints generally should only be accessible over -HTTPS. The recommended configuration for API endpoints is: - -```http -Content-Security-Policy: default-src 'none'; frame-ancestors 'none' -Strict-Transport-Security: max-age=63072000 -X-Content-Type-Options: nosniff -``` - -## Can other people see my test results? - -Anyone can choose to scan any domain, and the scan history for each domain is -public. However, HTTP Observatory does not store user data related to each scan. -In the old version of HTTP Observatory, users could choose to set their scan to -"public" or keep it private (the default), and there was a "recent scans" list -where domain names were listed. "Recent scans" was the main feature that users -would potentially wish to opt-out from, but it is no longer supported, hence -there is now no reason to provide the "public" flag. - -## When did the move occur? - -The new HTTP Observatory was launched on MDN on July 2, 2024. The old Mozilla -Observatory — containing HTTP Observatory plus other tools like TLS Observatory, -SSH Observatory, and Third-party tests — has been sunset in October 2024. - -> **Note:** Historic scan data has been preserved, and is included in the -> provided scan history for each domain. - -## What has changed after the migration? - -The MDN team has: - -- Updated the user experience to improve the site's look and make it easier to - use. For example, the recommendations highlighted by the test results are all - shown together, instead of one at a time. -- Updated the - [accompanying documentation](/en-US/docs/Web/Security/Practical_implementation_guides#content_security_fundamentals) - to bring it up to date and improve legibility. -- Changed the "rescan" checkbox and its underlying mechanics: - - There is no longer a rescan parameter. - - A site can only be scanned and a new result returned every 60 seconds. - - Deep-linking into a report initiates a rescan if the previous scan data is - older than 24 hours. -- Updated the - [tests](/en-US/observatory/docs/tests_and_scoring#tests-and-score-modifiers) - to bring them up-to-date with latest security best practices: - - Removed the out-of-date `X-XSS-Protection` test. - - Removed the out-of-date Flash and Silverlight (`clientaccesspolicy.xml` and - `crossdomain.xml`) embedding tests. - - Added a - [`Cross-Origin-Resource-Policy`](/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy) - (CORP) test. - - Updated the - [`Referrer-Policy`](/en-US/docs/Web/HTTP/Headers/Referrer-Policy) test to - update the score modifier for `referrer-policy-unsafe` and remove the - `referrer-policy-no-referrer-when-downgrade` result. - -## Has the HTTP Observatory API been updated to use the new tests? - -Yes. The new v2 API is available at an updated URL — -`https://observatory-api.mdn.mozilla.net/api/v2/scan` — and the response is now -more concise. For example, a [`POST`](/en-US/docs/Web/HTTP/Methods/POST) request -to `https://observatory-api.mdn.mozilla.net/api/v2/scan?host=mdn.net` will -return a JSON payload like this: - -```json -{ - "id": 53494870, - "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=mdn.dev", - "algorithm_version": 4, - "scanned_at": "2024-10-11T13:21:36.453Z", - "error": null, - "grade": "A+", - "score": 105, - "status_code": 200, - "tests_failed": 0, - "tests_passed": 10, - "tests_quantity": 10 -} -``` - -We have removed several fields that were of limited use for CI integration, like -the complete response header listing. The important metrics like `score` and -`grade` are still included. We encourage you to migrate to the new API as soon -as possible: The v1 endpoint will be shut down on October 31, 2024. - -For reference, the v1 API returned a JSON payload with the following structure: - -```json -{ - "algorithm_version": 3, - "end_time": "Fri, 11 Oct 2024 13:19:31 GMT", - "grade": "A+", - "hidden": false, - "likelihood_indicator": "LOW", - "response_headers": { - "Accept-Ranges": "none", - "Another-Header": "another-value" - }, - "scan_id": 56728847, - "score": 100, - "start_time": "Fri, 11 Oct 2024 13:19:30 GMT", - "state": "FINISHED", - "status_code": 200, - "tests_failed": 0, - "tests_passed": 10, - "tests_quantity": 10 -} -``` - -## Does the new HTTP Observatory provide specific TLS and certificate data? - -The previous Observatory site included specific results tabs containing TLS and -certificate analysis data. The new one does not, and there are currently no -plans to include these features: it provides a clear focus on HTTP data. - -## (Redirection) What is the HTTP redirection test assessing? - -This test is checking whether your web server is making its -[initial redirection from HTTP to HTTPS](/en-US/docs/Web/Security/Practical_implementation_guides/TLS#http_redirection), -on the same hostname, before doing any further redirections. This allows the -HTTP -[`Strict-Transport-Security`](/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) -(HSTS) header to be applied properly. - -For example, this redirection order is correct: - -`http://example.com` → `https://example.com` → `https://www.example.com` - -An incorrect (and penalized) redirection looks like this: - -`http://example.com` → `https://www.example.com` - -## (X-Frame-Options) What if I want to allow my site to be framed? - -As long as you are explicit about your preference by using the -[`Content-Security-Policy`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) -[`frame-ancestors`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) -directive, you will pass the -[`X-Frame-Options`](/en-US/docs/Web/HTTP/Headers/X-Frame-Options) test. For -example, to allow your site to be framed by any HTTPS site: - -```http -Content-Security-Policy: frame-ancestors https: -``` diff --git a/copy/observatory/tests_and_scoring.md b/copy/observatory/tests_and_scoring.md deleted file mode 100644 index 47cb05afd439..000000000000 --- a/copy/observatory/tests_and_scoring.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Tests & Scoring ---- - -# HTTP Observatory Scoring Methodology - -It is difficult to assign an objective value to a subjective question such as -"How bad is not implementing HTTP Strict Transport Security?" In addition, what -may be unnecessary for one site — such as implementing Content Security Policy — -might mitigate important risks for another. The scores and grades offered by the -Mozilla Observatory are designed to alert developers when they're not taking -advantage of the latest web security features. Individual developers will need -to determine which ones are appropriate for their sites. - -This page outlines the scoring methodology and grading system Observatory uses, -before listing all of the specific tests along with their score modifiers. - -## Scoring Methodology - -All websites start with a baseline score of 100, which is then modified with -penalties and/or bonuses resulting from the tests. The scoring is done across -two rounds: - -1. The baseline score has the penalty points deducted from it. -2. If the resulting score is 90 (A) or greater, the bonuses are then added to - it. You can think of the bonuses as extra credit for going above and beyond - the call of duty in defending your website. - -Each site tested by Observatory is awarded a grade based on its final score -after the two rounds. The minimum score is 0, and the highest possible score in -the HTTP Observatory is currently 145. - -## Grading Chart - -| Scoring Range | Grade | -| :-----------: | :-----------: | -| 100+ |  A+ | -| 90-99 |  A  | -| 85-89 |  A- | -| 80-84 |  B+ | -| 70-79 |  B  | -| 65-69 |  B- | -| 60-64 |  C+ | -| 50-59 |  C  | -| 45-49 |  C- | -| 40-44 |  D+ | -| 30-39 |  D  | -| 25-29 |  D- | -| 0-24 |  F  | - -The letter grade ranges and modifiers are essentially arbitrary, however, they -are based on feedback from industry professionals on how important passing or -failing a given test is likely to be. - -## Tests and Score Modifiers - -> **Note:** Over time, the modifiers may change as baselines shift or new -> cutting-edge defensive security technologies are created. The bonuses -> (positive modifiers) are specifically designed to encourage people to adopt -> new security technologies or tackle difficult implementation challenges. diff --git a/copy/plus/faq.md b/copy/plus/faq.md deleted file mode 100644 index 3afb52ce160d..000000000000 --- a/copy/plus/faq.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: FAQ ---- - -# Frequently asked questions - -## What is MDN Plus? - -MDN Plus is a premium subscription service launched in March 2022 by Mozilla. -The service allows users to customize their MDN Web Docs experience through -premium features such as [Updates](/en-US/plus/docs/features/updates), -[Collections](/en-US/plus/docs/features/collections) and -[MDN Offline](/en-US/plus/docs/features/offline). - -## Why are we working on premium features on MDN? - -The extensive research we have done in 2020 and 2021 showed us that MDN users -would appreciate a customized experience on MDN. We’ve got information on what -you would find useful and what you would be interested in. All the premium -features we propose today reflect that feedback. MDN Plus is an initial step -towards making the experience on the site more interactive and helpful for our -users. - -## How much does MDN Plus cost? - -A three-tiered pricing model has been put in place in order to try and -accommodate our users’ needs as much as possible: - -- _MDN Core_ - A free plan, for those ones who want to try out a limited version - of the premium features. -- _MDN Plus 5_ - A $5/month or $50/year plan that offers unlimited access to the - premium features included in MDN Plus. -- _MDN Supporter 10_ - A $10/month or $100/year plan for users who want to - support MDN with a higher amount. On top of the MDN Plus premium features, MDN - supporters will be able to contribute and shape the product moving forward, by - having early access to premium features and a direct feedback channel with the - MDN team. - -Subscribing for a yearly plan activates a 20% discount for all the paid options. - -## Can I upgrade/downgrade my plan? - -Currently, you can only upgrade your plan. For getting a downgrade, please -cancel your current subscription first and then activate the new one. - -## What is happening with the existing MDN Web Docs? - -Nothing. We will continue to develop & maintain our web documentation that will -remain free and accessible for everyone. There will be no change there. Even -more, we believe that MDN Web Docs will benefit from MDN Plus, as we plan to -reinvest part of the gains from MDN Plus and improve our documentation as well -as the overall user experience on the website. - -## Are we violating any OS license obligation by adding a paid product to MDN? - -MDN content is made available under a CC BY-SA 2.5 license. That license doesn't -preclude Mozilla (or other users of MDN content) from having a paid product. MDN -Plus adds premium features like updates and collections on top of the free -content. Regular users can still access and reuse MDN content under the Creative -Commons license. - -## Where will the money from MDN Plus go? - -Since its beginning in 2005, MDN Web Docs has been a project hosted and provided -by Mozilla. Mozilla covers the cost of infrastructure, development and -maintenance of the MDN platform, including a team of engineers and its own team -of dedicated writers. - -Mozilla wants MDN Plus to help ensure that MDN's open source content continues -to be supported into the future. MDN Plus has been built only with Mozilla -resources, and any revenue generated by MDN Plus will stay within Mozilla. We -are looking into ways to reinvest some of these additional funds into open -source projects contributing to MDN but it is still in the early stages. - -## Does the launch of MDN Plus impact the relationship with partners like OWD? - -The existence of a new subscription model will not detract from MDN's current -free Web Docs offering in any way. The current experience of accessing web -documentation will not change for users who do not wish to sign up for a premium -subscription. Open Web Docs (OWD) and Mozilla will continue to work closely -together on MDN for the best possible web platform documentation for everyone. -For more information about how our organizations work together, please check -[this article](https://hacks.mozilla.org/2022/03/mozilla-and-open-web-docs-working-together-on-mdn/). - -## What regions is MDN Plus available in? - -The free version of MDN Plus is available worldwide. Anyone can create an MDN -Plus account and try out a limited version of the premium features. As for the -paid plans, they are currently available as follows: in the United States, -Canada (since March 24th, 2022), Austria, Belgium, Finland, France, the United -Kingdom, Germany, Ireland, Italy, Malaysia, the Netherlands, New Zealand, Puerto -Rico, Sweden, Singapore, Switzerland, Spain (since April 28th, 2022), Estonia, -Greece, Latvia, Lithuania, Portugal, Slovakia and Slovenia (since June 15th, -2022). We are working on expanding this list even further. - -## I have an idea for MDN Plus, who should I contact? - -In case you have an idea you would like to share about MDN Plus, you can add -your suggestions to our [mdn-community](https://github.com/mdn/mdn-community) -repo. - -If a subscriber, you can also leave us feedback by accessing the ‘Feedback’ -option in the user menu. diff --git a/copy/plus/features/ai-help.md b/copy/plus/features/ai-help.md deleted file mode 100644 index 1197939e2667..000000000000 --- a/copy/plus/features/ai-help.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: AI Help ---- - -# AI Help - -> Get real-time assistance and support - -AI Help, available for both free and paid MDN Plus subscribers, utilizes OpenAI -GPT-4o mini for free users and GPT-4o for paying subscribers to enhance the MDN -experience. It offers quick and effective access to MDN's broad database. It -specializes in searching and summarizing MDN content to directly address your -queries. Additionally, for web development queries not covered in MDN, AI Help -draws on its external knowledge, always indicating when the sources are from -outside MDN. - -## Key Features - -- **Asking Questions**: You can ask your web development related questions - directly on MDN, in AI Help. -- **Content Search**: AI Help locates relevant articles from MDN's pages and - presents them to you. -- **Summary Generation**: It offers concise summaries as answers to your - questions, providing the option to explore the sources directly, read the - summary, or both. -- **Code Testing**: When articles include code examples, you can test the code - directly in the [MDN Playground](/en-US/play), allowing you to immediately - check the code accuracy. - -## How to Use AI Help - -Navigate to [AI Help](/en-US/plus/ai-help) via the top menu bar on MDN pages. - -If you're not logged in or don't have an MDN Plus account, you'll be prompted to -sign up or log in using your Mozilla Account. - -![Screenshot of AI Help page as non-logged in user, AI Help button highlighted as well as the Log in/Sign up options](/assets/plus-docs/ai-help/login-signup.png) - -Once logged in, you'll access AI Help's main page where you can select from the -suggested questions or input your own. - -AI Help will search MDN and display the consulted pages in real time with -summary links. - -![Screenshot of logged-in AI Help page, AI Help Search highlighted, questions inserted and answer generated](/assets/plus-docs/ai-help/example-question-answering.png) - -You’ll be able to **Edit** your question by using the edit option, and AI Help -will provide you with a new answer. - -![Screenshot of logged-in AI Help page, AI Help Edit option opened and highlighted, on the same question as above](/assets/plus-docs/ai-help/example-question-editing.png) - -### Chat History - -Enable chat history to save your interactions and come back later to them. - -![Screenshot of same logged-in AI Help page, AI Help Chat History highlighted with click on button ‘Enable History’](/assets/plus-docs/ai-help/history-banner.png) - -You can also manage your history directly from your Account Settings, and -disable or delete it at any time. - -![Screenshot of Account Settings page, with Chat History Enable and Delete highlighted’](/assets/plus-docs/ai-help/history-settings.png) - -### Code Testing - -Select code examples and test them in the MDN Playground for a quick check of -code accuracy and a seamless coding experience. - -![Screenshot of an AI Help answer with code examples that are being added to a list for sending them to the Playground](/assets/plus-docs/ai-help/code-examples-queue.png) - -![Screenshot with code examples opened in the Playground](/assets/plus-docs/ai-help/code-examples-playground.png) - -### Feedback - -You can rate answers using the thumbs-up/down mechanism. - -![Screenshot with thumbs up/down highlighted](/assets/plus-docs/ai-help/rate-answers.png) - -If you think an answer is incorrect or unhelpful, file an issue using the -provided template, and one of our engineers will look into it and get back to -you quickly. - -![Screenshot with Github issue template open](/assets/plus-docs/ai-help/issue-template.png) - -You can also use the dedicated feedback link on the AI Help page for general -feedback about the feature. - -![Screenshot with the general feedback link highlighted](/assets/plus-docs/ai-help/report-feedback.png) - -Thank you for using AI Help to enhance your MDN experience! diff --git a/copy/plus/features/collections.md b/copy/plus/features/collections.md deleted file mode 100644 index 50b301f9891f..000000000000 --- a/copy/plus/features/collections.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -title: Collections ---- - -# Collections - -> MDN. Hand _selected_ by you. -> -> Collections allow you to save MDN articles and share your library across -> devices. We also automatically save for you the pages you visit most -> frequently. They will help you find what you need quicker by showing first in -> your search results when looking for a relevant topic and you’ll be able to -> curate the lists to your liking. - -## Getting started - -To start creating your Collections, **Save a page** first. - -### Desktop - -1. Select **Save** at the top of the page. - ![Screenshot showing save button highlighted at the top right of the page.](/assets/plus-docs/collections/desktop-saving-page.png) -2. Click **Save** in the dialog that opens. - ![Screenshot showing collections dialog with save button highlighted.](/assets/plus-docs/collections/desktop-page-dialog-save.png) - -### Mobile - -1. **Open the ⋮ menu** - ![Screenshot showing three dot button highlighted at the top right of the page.](/assets/plus-docs/collections/mobile-open-article-actions.png) -2. Tap on **Save**. - ![Screenshot showing the save menu entry highlighted.](/assets/plus-docs/collections/mobile-save-page.png) -3. In the next view that opens, tap **Save** - ![Screenshot showing the save collection item view. This contains two inputs and two buttons one of which is the save button.](/assets/plus-docs/collections/mobile-save-page-step-one.png) - -## Reaching the Collections page - -When an article is saved, it appears in **Collections**. - -### Desktop - -1. Click on your avatar at the top-right and select **Collections**. - ![Screenshot showing the user menu entry expanded. This reveals a number of options the second of which is Collections.](/assets/plus-docs/collections/desktop-collections-user-menu.png) - -### Mobile - -1. Open the main menu by tapping on the **burger menu icon** at the top right of - the page. - ![Screenshot showing the burger menu icon highlighted.](/assets/plus-docs/collections/mobile-burger-menu.png) -2. Click on your avatar / email address at the bottom of the menu. - ![Screenshot showing the expanded user menu.](/assets/plus-docs/collections/mobile-menu.png) -3. From the submenu, tap on **Collections**. - ![Screenshot showing the expanded submenu with Collections highlighted.](/assets/plus-docs/collections/mobile-collections-menu-item.png) - -## The Collections page overview - -Your saved articles will appear on the collections dashboard accessible from the -**MDN Plus → Collections** link. - -### Desktop - -![Screenshot showing the collections dashboard. The dashboard shows a list of all pages you have saved.](/assets/plus-docs/collections/collections-dashboard.png) - -### Mobile - -![Screenshot showing the collections dashboard on mobile. The dashboard shows a list of all pages you have saved.](/assets/plus-docs/collections/mobile-collections-dashboard.png) - -## Adding notes - -### Desktop - -Add notes from **an article page** - -1. Select **Saved** at the top of the page. - ![Screenshot showing and article page that has been saved to your collections. The saved button located at the top right of the page is highlighted.](/assets/plus-docs/collections/desktop-page-dialog-save.png) -2. Type the note you’d like to add in the **Note** field and select **Save**. - ![Screenshot showing the collection dialog. It contains two input fields and two buttons. The second input field is for notes.](/assets/plus-docs/collections/desktop-page-add-note.png) - -Add notes from **Collections** - -1. Click the **⋮ menu** to the right of the bookmark and select **Edit**. - ![Screenshot showing the collection dashboard. On the right of an entry is a three dot menu item which is highlighted](/assets/plus-docs/collections/desktop-collections-three-dot-menu.png) -2. Select **Edit**. - ![Screenshot showing the expanded three dot menu. This reveals two options, the first of which is edit.](/assets/plus-docs/collections/desktop-collections-edit-menu.png) -3. Type the note you’d like to add in the **Note** field and select **Save**. - ![Screenshot showing the edit collection entry dialog. It contains two input fields and two buttons. The second input field is for notes.](/assets/plus-docs/collections/desktop-collections-edit-dialog-add-note.png) - -### Mobile - -Add notes from **an article page** - -1. Click the **⋮ menu** to the right of the saved article - ![Screenshot showing the three dot menu at the top right.](/assets/plus-docs/collections/mobile-open-article-actions.png) -2. Select **Saved**. - ![Screenshot showing the article actions menu with the saved menu entry highlighted.](/assets/plus-docs/collections/mobile-saved-page.png) -3. Type the note you’d like to add in the **Note** field and select **Save**. - ![Screenshot showing the edit saved collection entry view. It contains two input fields and two buttons. The second input field is for notes.](/assets/plus-docs/collections/mobile-add-note.png) - -Add notes from **Collections** - -1. Click the **⋮ menu** to the right of the saved article and select **Edit**. - ![Screenshot showing the expanded three dot menu located to the right of a collection entry. The first option is edit.](/assets/plus-docs/collections/mobile-collections-dashboard-edit.png) -2. Type the note you’d like to add in the **Note** field and select **Save**. - ![Screenshot showing the edit saved collection entry view. It contains two input fields and two buttons. The second input field is for notes.](/assets/plus-docs/collections/mobile-add-note.png) - -## Removing a saved page - -### Desktop - -Remove a saved page from **an article page** - -1. Select **Saved** at the top of the page. - ![Screenshot showing and article page that has been saved to your collections. The saved button located at the top right of the page is highlighted.](/assets/plus-docs/collections/desktop-page-dialog-save.png) -2. Select **Delete**. - ![Screenshot showing the collection dialog. It contains two input fields and two buttons. The second button is delete, which is also highlighted](/assets/plus-docs/collections/desktop-remove-saved-delete.png) - -Remove a saved page from **Collections** - -1. Click the **⋮ menu** to the right of the saved page and select **Delete**. - ![Screenshot showing the expanded three dots icon. There are two options, the second of which is delete.](/assets/plus-docs/collections/desktop-collections-dashboard-delete.png) -2. Your saved page has now been removed. Select **Undo** in the notification at - the bottom of the screen to revert this action. - ![Screenshot showing the undo toast dialog at the bottom of the page. The undo button located on the right is highlighted](/assets/plus-docs/collections/desktop-collections-undo.png) - -### Mobile - -Remove a saved page from **an article page** - -1. Click the **⋮ menu** to the right of the saved article - ![Screenshot showing the three dot menu at the top right.](/assets/plus-docs/collections/mobile-open-article-actions.png) -2. Select **Saved**. - ![Screenshot showing the article actions menu with the saved menu entry highlighted.](/assets/plus-docs/collections/mobile-saved-page.png) -3. Select **Delete**. - ![Screenshot showing the edit view on mobile. It contains two input fields and two buttons. The second button is delete, which is also highlighted](/assets/plus-docs/collections/mobile-collections-delete-entry.png) - -Remove a saved page from **Collections** - -1. Click the **⋮ menu** to the right of the saved page and select **Delete**. - ![Screenshot showing the expanded three dots icon. There are two options, the second of which is delete.](/assets/plus-docs/collections/mobile-collections-dashboard-delete-entry.png) -2. Your saved page has now been removed. Select **Undo** in the notification at - the bottom of the screen to revert this action. - ![Screenshot showing the undo toast dialog at the bottom of the page. The undo button located on the right is highlighted](/assets/plus-docs/collections/mobile-collections-undo.png) - -## Filtering saved pages - -Saved pages can be filtered by searching Title keywords through the page search -bar. - -![Screenshot showing collections dashboard highlighting text inside the filter input element.](/assets/plus-docs/collections/desktop-collections-filter.png) - -## Sorting saved pages - -Saved pages can be sorted by Date added and Title. The input element is located -to the right of the Collections search input. - -![Screenshot showing collections dashboard with sort element expanded showing the date and title sorting options.](/assets/plus-docs/collections/desktop-collections-sort.png) - -## Frequently viewed articles - -These are collections we automatically create for you, based on your activity -while being logged into MDN Plus. As an MDN Plus user, you are automatically -opted into this feature. - -![Screenshot showing collections dashboard with the frequently viewed articles tab active.](/assets/plus-docs/collections/desktop-collections-fva.png) - -## How are these articles generated? - -Frequently viewed pages are articles you visit most frequently while logged into -MDN Plus. We will always show you your most recent top viewed 20 pages. - -## Remove a saved page from Frequently viewed articles - -### Desktop - -1. Click the **⋮ menu** to the right of the saved page and select **Delete**. - ![Screenshot showing the expanded three dots icon. There are two options, the second of which is delete.](/assets/plus-docs/collections/desktop-collections-delete-fva.png) -2. Your saved page has now been removed. Select **Undo** in the notification at - the bottom of the screen to revert this action. - ![Screenshot showing the undo toast dialog at the bottom of the page. The undo button located on the right is highlighted](/assets/plus-docs/collections/desktop-collections-undo.png) - -### Mobile - -Click the **⋮ menu** to the right of the saved page and select **Delete**. Your -saved page has now been removed. Select **Undo** in the notification at the -bottom of the screen to revert this action. - -1. Click the **⋮ menu** to the right of the saved page and select **Delete**. - ![Screenshot showing the expanded three dots icon. There are two options, the second of which is delete.](/assets/plus-docs/collections/desktop-collections-delete-fva.png) -2. Your saved page has now been removed. Select **Undo** in the notification at - the bottom of the screen to revert this action. - ![Screenshot showing the undo toast dialog at the bottom of the page. The undo button located on the right is highlighted](/assets/plus-docs/collections/mobile-collections-fva-undo.png) diff --git a/copy/plus/features/offline.md b/copy/plus/features/offline.md deleted file mode 100644 index 9a42178d726c..000000000000 --- a/copy/plus/features/offline.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: MDN Offline ---- - -# MDN Offline - -> _Web docs without web access_: the full power of MDN, offline -> -> Leverage the offline capability of our **MDN PWA** to work on the go. Whether -> you're in a high-speed train, a cabin in the woods or just looking to save -> some data, MDN Offline gives you access to the full power of your favorite dev -> resource, so your projects aren't interrupted. The site is snappier and your -> experience better. - -When you need access to MDN even without an internet connection, **MDN Offline** -allows you to browse the most up to date version of the site, or simply to have -a faster experience while saving data. - -## Getting started - -To start using MDN Offline, you must first **Enable offline storage**. - -1. Click on your avatar(top-right) and open the **user menu → My Settings** - ![Screenshot showing expanded user menu revealing the MDN Offline menu option.](/assets/plus-docs/offline/desktop-offline-user-menu.png) -2. Under **MDN Offline** use the **Enable offline storage** switch. - ![Screenshot showing MDN Offline page with the enable offline toggle highlighted.](/assets/plus-docs/offline/desktop-offline-enable-offline.png) - -You can also add it to your homescreen for an experience similar to using a -native app. - -## Choose how to stay up-to-date - -1. Enable offline storage - ![Screenshot showing MDN Offline page with the enable offline toggle highlighted.](/assets/plus-docs/offline/desktop-offline-enable-offline.png) -2. Choose how to update -3. Manually update by clicking **Update now** or **Enable auto-update** - ![Screenshot showing MDN Offline page with the auto update toggle highlighted.](/assets/plus-docs/offline/desktop-offline-enable-auto-update.png) -4. Clicking **Update now** will start the download of the latest version of MDN - Web Docs. - ![Screenshot showing MDN Offline page with the update now button highlighted.](/assets/plus-docs/offline/desktop-offline-manual-update.png) -5. The date of the last update is also shown. - -## Clear stored data - -Open the user menu → MDN Offline → Clear data - -![Screenshot showing MDN Offline page with the clear data button highlighted.](/assets/plus-docs/offline/desktop-offline-clear-data.png) - -## Supported Features - -Some insight into what can be expected from using MDN Offline - -### Browsing Content - -If offline mode is enabled, offline content is preferred. All content works -without an internet connection, with the exception of a few github-based -examples and large video files. You can also indicate you prefer offline content -even when online. - -> NOTE: MDN Offline cannot be used while in a private or incognito window. diff --git a/copy/plus/features/overview.md b/copy/plus/features/overview.md deleted file mode 100644 index a6d91f6c9fa3..000000000000 --- a/copy/plus/features/overview.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Feature Overview ---- - -# Overview - -> More MDN. Your MDN. _Get started_. -> -> This page is an overview of the MDN Plus documentation and related resources. - -MDN Plus is a premium subscription service launched by Mozilla. The service -allows users to customize their MDN Web Docs experience through premium features -such as Collections, filtering Updates and MDN Offline. - -Learn more about MDN Plus on our [website](/) or in this -[blogpost](https://hacks.mozilla.org/2022/03/introducing-mdn-plus-make-mdn-your-own/). diff --git a/copy/plus/features/playground.md b/copy/plus/features/playground.md deleted file mode 100644 index 98acf32f6f23..000000000000 --- a/copy/plus/features/playground.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Playground ---- - -# Playground - -> Write,Test and _Share_ your code - -## What is the Playground? - -The Playground is the new web development tool provided by MDN. It serves as a -platform for web developers to preview and experiment with HTML, CSS, and -JavaScript code. The Playground offers features like basic autocomplete, code -formatting using the popular "prettier" tool, and the ability to share your work -with others. By integrating the Playground into our web docs, MDN aims to -provide an enhanced learning and coding experience for developers. - -## Key Features - -The MDN Playground comes packed with several key features, including: - -**Preview:** Instantly see the results of your HTML, CSS, and JavaScript code. - -**Autocomplete:** Benefit from basic code suggestions and auto-completion to -speed up your coding process. - -**Code Formatting:** Utilize the powerful "prettier" tool to automatically -format your code for better readability. - -**Sharing:** Share your amazing work with others by publishing your code and -sharing the generated link. - -**Integration within MDN:** Seamlessly access the Playground within MDN, -enabling a comprehensive learning experience. - -## How to Access the MDN Playground - -Accessing the MDN Playground is quick and easy. Follow these steps to start -using the Playground: - -1. There are two ways to access the playground: a. directly from the MDN menu by - clicking on “Play” b. by accessing any MDN documentation page including code - samples and clicking on the playground icon within the code samples - ![Screenshot of top menu with play highlighted](/assets/plus-docs/playground/playground-menu.png) - ![Screenshot of a code example with play highlighted](/assets/plus-docs/playground/playground-sample.png) -2. Clicking the "Playground" button will launch the Playground in a new tab. -3. Start coding, previewing, and experimenting with HTML, CSS, and JavaScript - right away! - ![Screenshot of the playground](/assets/plus-docs/playground/playground-example.png) - -## Join the Community - -The MDN Playground is not just a tool; it's a community of passionate developers -eager to learn and collaborate. We encourage you to join the MDN Playground -community and become part of this vibrant ecosystem. Here's how you can get -involved: - -Sign up for an MDN Plus account if you haven't already. - -1. Participate in discussions, share ideas, and seek help on - [Discord](/discord). -2. Contribute to the improvement of the Playground by - [reporting issues](https://github.com/mdn/yari/issues/new?template=bug-report.yml) - or - [suggesting new features](https://github.com/mdn/mdn/issues/new?template=content-or-feature-suggestion.yml). -3. Showcase your projects, share your knowledge, and inspire others by - contributing code examples to MDN. - -## Under the Hood - -Curious about how the Playground works? Visit our blog and read more about the -technical details, architecture, and design choices we made to build it. diff --git a/copy/plus/features/updates.md b/copy/plus/features/updates.md deleted file mode 100644 index 5c23532a8469..000000000000 --- a/copy/plus/features/updates.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Updates ---- - -# Updates - -> Stay _up to date_ with MDN Updates -> -> Whether Web APIs, JavaScript, CSS, HTTP, or HTML, MDN Web Docs reflects the -> ever-changing landscape for features across the most popular browsers and -> devices with detailed documentation and guidance geared towards developers. - -When you're developing for the Web, you need to make sure you're building -applications with well-supported features to give your users the best -experience. Choosing new Web features means that you need to keep an eye on -compatibility changes as vendors frequently add, update, or remove support for -Web platform technologies. - -MDN Updates is a feature that helps you navigate and curate Web platform -technology support via a stream of updates. The results organized in the stream -of updates show compatibility by feature across fourteen different browser -engines, from iOS and Android to desktop and server platforms. - -Features are categorized by technology like CSS, HTML, JavaScript, HTTP, and -others to let you focus on the technologies that impact your development -projects. - -MDN Plus Updates lets you quickly get an overview of new, experimental, and -upcoming browser support, new sub-features under a major feature, deprecated or -removed support, and changes to existing browser compatibility data entries. - -## Using MDN Plus Updates - -To use Updates, navigate to the [MDN Plus Updates](/en-US/plus/updates) page, -where you can see a list of all changes in browser support for features on MDN -Web Docs listed by date. - -![Screenshot of default view](/assets/plus-docs/updates/updates.png) - -For each feature, updates display the release version and the date when browser -support changed. Expanding the update shows Browser Compatibility Tables to -indicate support across all browsers and devices. The feature update includes -links to MDN Web Docs pages with clear documentation and guidance on how to use -it. - -![Expanded feature screenshot with the table, link to docs, watch and save](/assets/plus-docs/updates/updates_bcd.png) - -## Filtering and searching web platform updates - -By default, the list of updates shows all changes grouped by browser release -version and date. Selecting a browser from the dropdown menu will filter the -list of changes to only show changes for that browser. You can select a category -from the dropdown menu to only show changes for that technology category or -combine that with a browser filter to show only changes for a specific browser -and technology category. - -![Filtered screenshot, browser and category](/assets/plus-docs/updates/updates_filter.png) - -You can also search for a specific feature by name or keyword to find the -functionality you're looking for. - -![Search screenshot"](/assets/plus-docs/updates/updates_filter.png) - -## Curating your own collection of updates - -Aside from Browser Compatibility Tables and links to the MDN Web Docs pages, -expanding feature details provides an additional option to **Save** the feature. -Saving a feature will add it to a curated collection of features you want to -track. You can create multiple collections to organize and group features that -matter most for your applications and projects. - -Saving a feature to a collection allows you to add the feature to a collection -of saved features. You can create multiple collections to organize and group -features you want to track. - -![Screenshot of multiple collections](/assets/plus-docs/updates/collections.png) - -To view your collection of saved features, click the **Saved** tab at the top of -the Updates page. - -![Screenshot showing the multiple collections on the updates page](/assets/plus-docs/updates/updates_collection.png) - -Visit the [MDN Plus Updates](/en-US/plus/updates) page and give us feedback. diff --git a/docs/envvars.md b/docs/envvars.md index 128ab565590f..2f600f9bec9e 100644 --- a/docs/envvars.md +++ b/docs/envvars.md @@ -50,6 +50,12 @@ https://github.com/mdn/mdn-contributor-spotlight. Path to the curriculum content, cloned from https://github.com/mdn/curriculum. +### `GENERIC_CONTENT_ROOT` + +**Default: `../generic-content/files`** + +Path to the generic content. + ### `BUILD_FOLDERSEARCH` **Default: ``** (meaning, none) diff --git a/libs/env/index.d.ts b/libs/env/index.d.ts index f57b38a5ed1b..f29865853a34 100644 --- a/libs/env/index.d.ts +++ b/libs/env/index.d.ts @@ -16,6 +16,7 @@ export const CONTENT_TRANSLATED_ROOT: string; export const CONTRIBUTOR_SPOTLIGHT_ROOT: string; export const BLOG_ROOT: string; export const CURRICULUM_ROOT: string; +export const GENERIC_CONTENT_ROOT: string; export const REPOSITORY_URLS: { [path: string]: string; }; diff --git a/libs/env/index.js b/libs/env/index.js index 7f9e65be1a13..5b976a14be24 100644 --- a/libs/env/index.js +++ b/libs/env/index.js @@ -92,6 +92,10 @@ export const BLOG_ROOT = correctContentPathFromEnv("BLOG_ROOT"); export const CURRICULUM_ROOT = correctPathFromEnv("CURRICULUM_ROOT"); +export const GENERIC_CONTENT_ROOT = correctContentPathFromEnv( + "GENERIC_CONTENT_ROOT" +); + // This makes it possible to know, give a root folder, what is the name of // the repository on GitHub. // E.g. `'https://github.com/' + REPOSITORY_URLS[document.fileInfo.root]` From c9437ce4412874b66cf4429162c07524c67109e8 Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Fri, 6 Dec 2024 14:12:02 +0000 Subject: [PATCH 4/5] feat: new about page (#12069) https://mozilla-hub.atlassian.net/browse/MP-1362 --------- Co-authored-by: Florian Dieminger --- build/spas.ts | 10 +- client/src/about/_mixins.scss | 282 ++++++ client/src/about/custom-elements.js | 76 ++ client/src/about/index.scss | 835 +++++++++++++++++- client/src/about/index.tsx | 263 ++++-- client/src/about/testimonial/index.scss | 64 -- client/src/about/testimonial/index.tsx | 28 - client/src/about/testimonial/quote.svg | 3 - client/src/app.scss | 1 - client/src/app.tsx | 2 +- client/src/assets/about/accurate-sm.svg | 1 + client/src/assets/about/accurate.svg | 1 + client/src/assets/about/building-dark.svg | 1 + client/src/assets/about/building.svg | 1 + client/src/assets/about/collaborative-sm.svg | 1 + client/src/assets/about/collaborative.svg | 1 + client/src/assets/about/dot-dark.svg | 1 + client/src/assets/about/dot.svg | 1 + client/src/assets/about/education.svg | 1 + .../src/assets/about/global-impact-dark.svg | 1 + client/src/assets/about/global-impact.svg | 1 + client/src/assets/about/handshake.svg | 1 + client/src/assets/about/inclusive-sm.svg | 1 + client/src/assets/about/inclusive.svg | 1 + client/src/assets/about/line-dot.svg | 1 + client/src/assets/about/sparkle.svg | 1 + .../assets/about/text-box-check-outline.svg | 1 + client/src/assets/about/web-check.svg | 1 + client/src/assets/lines.svg | 1 + client/src/community/index.scss | 191 +--- client/src/community/index.tsx | 90 +- client/src/telemetry/constants.ts | 1 + libs/constants/index.js | 1 + 33 files changed, 1425 insertions(+), 441 deletions(-) create mode 100644 client/src/about/_mixins.scss create mode 100644 client/src/about/custom-elements.js delete mode 100644 client/src/about/testimonial/index.scss delete mode 100644 client/src/about/testimonial/index.tsx delete mode 100644 client/src/about/testimonial/quote.svg create mode 100644 client/src/assets/about/accurate-sm.svg create mode 100644 client/src/assets/about/accurate.svg create mode 100644 client/src/assets/about/building-dark.svg create mode 100644 client/src/assets/about/building.svg create mode 100644 client/src/assets/about/collaborative-sm.svg create mode 100644 client/src/assets/about/collaborative.svg create mode 100644 client/src/assets/about/dot-dark.svg create mode 100644 client/src/assets/about/dot.svg create mode 100644 client/src/assets/about/education.svg create mode 100644 client/src/assets/about/global-impact-dark.svg create mode 100644 client/src/assets/about/global-impact.svg create mode 100644 client/src/assets/about/handshake.svg create mode 100644 client/src/assets/about/inclusive-sm.svg create mode 100644 client/src/assets/about/inclusive.svg create mode 100644 client/src/assets/about/line-dot.svg create mode 100644 client/src/assets/about/sparkle.svg create mode 100644 client/src/assets/about/text-box-check-outline.svg create mode 100644 client/src/assets/about/web-check.svg create mode 100644 client/src/assets/lines.svg diff --git a/build/spas.ts b/build/spas.ts index 62e52645f654..6d500d2877b6 100644 --- a/build/spas.ts +++ b/build/spas.ts @@ -25,7 +25,12 @@ import { } from "../libs/env/index.js"; import { isValidLocale } from "../libs/locale-utils/index.js"; import { DocFrontmatter, DocParent, NewsItem } from "../libs/types/document.js"; -import { getSlugByBlogPostUrl, makeTOC } from "./utils.js"; +import { + getSlugByBlogPostUrl, + injectLoadingLazyAttributes, + makeTOC, + postProcessExternalLinks, +} from "./utils.js"; import { findByURL } from "../content/document.js"; import { buildDocument } from "./index.js"; import { findPostBySlug } from "./blog.js"; @@ -309,6 +314,8 @@ export async function buildSPAs(options: { }; const [$] = await kumascript.render(url, {}, d); wrapTables($); + postProcessExternalLinks($); + injectLoadingLazyAttributes($); const [sections] = await extractSections($); const toc = makeTOC({ body: sections }); @@ -355,6 +362,7 @@ export async function buildSPAs(options: { OBSERVATORY_TITLE ); await buildStaticPages(path.join(GENERIC_CONTENT_ROOT, "community")); + await buildStaticPages(path.join(GENERIC_CONTENT_ROOT, "about")); } // Build all the home pages in all locales. diff --git a/client/src/about/_mixins.scss b/client/src/about/_mixins.scss new file mode 100644 index 000000000000..eb3522309b7e --- /dev/null +++ b/client/src/about/_mixins.scss @@ -0,0 +1,282 @@ +@use "../ui/vars" as *; +@use "../ui/atoms/button/mixins" as button; + +@mixin theme-setup { + .light & { + @content (light); + } + + .dark & { + @content (dark); + } + + // OS Default. + :root:not(.light):not(.dark) & { + @media (prefers-color-scheme: light) { + @content (light); + } + + @media (prefers-color-scheme: dark) { + @content (dark); + } + } +} + +@mixin layout { + h2, + h3, + p { + margin: 0; + } + + h2, + h3 { + color: var(--layout-text-primary); + + a { + color: unset; + text-decoration: none; + } + } + + a { + text-decoration: underline; + + &:hover { + text-decoration: none; + } + } + + p + p { + margin-top: 1.5rem; + } + + section { + margin-left: auto; + margin-right: auto; + max-width: var(--max-width); + padding-left: var(--gutter); + padding-right: var(--gutter); + width: 100%; + } + + h2 { + font-size: 2rem; + font-weight: 600; + margin-bottom: 1rem; + + @media (max-width: $screen-md) { + font-size: 1.375rem; + } + } +} + +@mixin header { + background: linear-gradient( + to top, + var(--header-next-section-bg, transparent) 0%, + var(--header-next-section-bg, transparent) + calc(var(--header-stats-height) / 2), + var(--header-bg) calc(var(--header-stats-height) / 2), + var(--header-bg) 100% + ); + + @media (max-width: $screen-md) { + padding-top: 1rem; + } + + section { + padding-top: 5rem; + + @media (max-width: $screen-md) { + padding-top: 0; + } + } + + h1 { + color: var(--header-text-primary); + font-size: 2.5rem; + margin-bottom: 1rem; + + @media (max-width: $screen-md) { + font-size: 2rem; + } + } + + p { + color: var(--header-text-secondary); + margin-bottom: 1.5rem; + } + + + section { + margin-top: 4.56rem; + + @media (max-width: $screen-md) { + margin-top: 2rem; + } + } +} + +@mixin stats { + background: var(--stats-bg); + border-radius: 0.5rem; + box-shadow: var(--stats-box-shadow); + color: var(--stats-text-primary); + display: flex; + gap: 1rem; + justify-content: space-around; + margin-top: 5em; + padding: 1rem; + position: relative; + text-align: center; + z-index: 2; + + @media (max-width: $screen-md) { + flex-wrap: wrap; + margin-top: 2rem; + } + + li { + align-items: baseline; + column-gap: 1rem; + display: flex; + flex-wrap: wrap; + justify-content: center; + min-width: 7.75rem; + overflow-wrap: anywhere; + + @media (max-width: $screen-md) { + align-items: center; + flex: 1; + flex-direction: column; + justify-content: flex-start; + } + + strong { + align-items: center; + background: var(--stats-stat-bg); + border-radius: 50%; + color: var(--stats-stat-text); + display: inline-flex; + height: 3.75rem; + justify-content: center; + width: 3.75rem; + } + } +} + +@mixin section { + column-gap: min(5rem, 5vw); + display: grid; + grid-template-columns: 4fr 6fr; + + @media (max-width: $screen-md) { + display: block; + } + + > * { + min-width: 0; + } +} + +@mixin boxes { + display: grid; + gap: 2rem; + grid-auto-rows: 1fr; + grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); + + li { + align-items: center; + background: var(--boxes-bg); + border: 1px solid var(--boxes-border); + border-radius: 0.5rem; + box-shadow: var(--boxes-shadow); + display: flex; + flex-direction: column; + gap: 1.5rem; + justify-content: space-between; + padding: 1.5rem; + text-align: center; + + h3, + h4, + h5, + h6 { + align-self: stretch; + background: var(--boxes-header-bg); + border-radius: 0.5rem 0.5rem 0 0; + color: var(--boxes-header-color); + font-size: 1.25rem; + font-weight: 500; + margin: -1.5rem; + margin-bottom: 0; + padding: 1.5rem; + } + + p { + color: var(--boxes-main-color); + margin: 0; + } + } +} + +@mixin stairs { + --stairs-icon-size: 3.125rem; + --stairs-step-indent: 3.125rem; + --stairs-step-gap: 4rem; + + li { + --stairs-padding-left: calc(var(--stairs-step-indent) * var(--nth-child)); + align-items: center; + display: flex; + gap: 1rem; + padding-left: var(--stairs-padding-left); + position: relative; + + @media (max-width: $screen-md) { + --stairs-step-indent: 0; + --stairs-padding-left: var(--stairs-icon-size); + --stairs-step-gap: 1rem; + } + + &:not(:last-of-type) { + margin-bottom: var(--stairs-step-gap); + } + + &::before { + background: var(--stairs-color); + content: ""; + display: block; + flex-shrink: 0; + height: var(--stairs-icon-size); + margin-left: calc(-1 * var(--stairs-icon-size)); + mask-image: var(--stairs-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: 80%; + width: var(--stairs-icon-size); + } + + &:not(:last-of-type)::after { + --height: calc(var(--stairs-step-gap) * 1.2); + background: linear-gradient(to bottom, var(--stairs-color), transparent); + bottom: calc(-1 * var(--height)); + content: ""; + display: block; + height: var(--height); + left: calc(var(--stairs-padding-left) - 50px); + mask: url("../assets/lines.svg"); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + position: absolute; + width: calc(var(--stairs-icon-size) + var(--stairs-step-indent)); + } + } + + @for $i from 1 through 4 { + li:nth-child(#{$i}) { + --nth-child: #{$i}; + } + } +} diff --git a/client/src/about/custom-elements.js b/client/src/about/custom-elements.js new file mode 100644 index 000000000000..35df7bcbb4d9 --- /dev/null +++ b/client/src/about/custom-elements.js @@ -0,0 +1,76 @@ +import { LitElement } from "lit"; + +export class MDNImageHistory extends LitElement { + createRenderRoot() { + return this; + } + + firstUpdated() { + this.renderRoot.querySelectorAll("img").forEach((img) => { + const regex = /@([0-9]+(?:\.[0-9]+)?)(?=x\.[a-z]+$)/; + const match = img.src.match(regex); + if (match?.[1]) { + const baseRes = parseFloat(match[1]); + const dpis = [1, 2]; + img.srcset = dpis + .map( + (dpi) => `${img.src.replace(regex, `@${baseRes * dpi}`)} ${dpi}x` + ) + .join(", "); + } + }); + } +} + +customElements.define("mdn-image-history", MDNImageHistory); + +export class TeamMember extends LitElement { + _setID() { + const hx = this.querySelector("h4, h5"); + const panel = hx?.closest(".tabpanel"); + if (hx && panel) { + const id = `${panel.id.replace("-panel", "")}_${hx.id}`; + if (this.id !== id) { + this.id = id; + } + } + } + + /** @param {FocusEvent} ev */ + _focusin({ currentTarget }) { + if (currentTarget instanceof HTMLElement) { + window.history.pushState({}, "", `#${currentTarget.id}`); + this.scrollIntoView({ block: "nearest", inline: "nearest" }); + } + } + + /** @param {MouseEvent} ev */ + _mousedown(ev) { + if (ev.target instanceof HTMLAnchorElement) { + ev.preventDefault(); + } + } + + createRenderRoot() { + return this; + } + + connectedCallback() { + super.connectedCallback(); + this.tabIndex = 0; + this._setID(); + this.addEventListener("mousedown", this._mousedown); + this.addEventListener("focusin", this._focusin); + if (window.location.hash === `#${this.id}`) { + setTimeout(() => this.focus(), 0); + } + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.removeEventListener("mousedown", this._mousedown); + this.removeEventListener("focusin", this._focusin); + } +} + +customElements.define("team-member", TeamMember); diff --git a/client/src/about/index.scss b/client/src/about/index.scss index 3388f85691c9..4b67acbc5f23 100644 --- a/client/src/about/index.scss +++ b/client/src/about/index.scss @@ -1,55 +1,820 @@ @use "../ui/vars" as *; +@use "../ui/mixins" as *; +@use "../about/mixins" as about; -.about { - width: 100%; +main.about-container { + --about-stats-height: 5.75rem; + --about-section-gap: 5rem; + --max-width: 74rem; + --inner-width: calc(min(var(--max-width), 100vw) - 2 * var(--gutter)); - .about-container { - margin: 0 auto; - max-width: 52rem; - padding: 0 1rem 2rem; + background: var(--about-bg-primary); + color: var(--about-color); - h1 { - margin-top: 3rem; + @media (max-width: $screen-md) { + --about-section-gap: 3rem; + } + + @include about.layout; + + @include about.theme-setup using ($mode) { + @if $mode == light { + --header-next-section-bg: #f2f2f5; + --header-text-primary: #000; + --header-text-secondary: #343434; + --header-bg: #fff; + --stats-bg: #fff; + --stats-box-shadow: 4px -2px 15px 0 rgba(179, 179, 179, 0.2), + 4px -4px 15px 0 rgba(179, 179, 179, 0.15); + --stats-text-primary: #000; + --stats-stat-bg: #d7f5dc; + --stats-stat-text: #007936; + --boxes-bg: #fff; + --boxes-border: none; + --boxes-shadow: -4px 4px 8px 0 rgba(179, 179, 179, 0.15), + 4px 4px 8px 0 rgba(179, 179, 179, 0.18); + --boxes-header-bg-1: #d5e8fb; + --boxes-header-color-1: inherit; + --boxes-header-bg-2: #fbe3d5; + --boxes-header-color-2: inherit; + --boxes-header-bg-3: #fbf7d5; + --boxes-header-color-3: inherit; + --boxes-header-bg-4: #fbd5d5; + --boxes-header-color-4: inherit; + --boxes-header-bg-5: #dfd5fb; + --boxes-header-color-5: inherit; + --boxes-main-color: #000; + --stairs-color: #007936; + --about-bg-primary: #fff; + --about-bg-secondary: #f2f2f5; + --about-join-us-bg: #f2f2f5; + --about-join-us-border: none; + --about-join-us-color: #343434; + --about-join-us-image: url("../assets/about/building.svg"); + --about-tablist-border: #858585; + --about-tablist-color: rgba(0, 0, 0, 0.6); + --about-tablist-active-border: #007936; + --about-tablist-active-color: #000; + --about-color: #000; + --about-heading-color: #000; + --about-core-values-bg: #fff; + --about-core-values-bg-secondary: #d7f5dc; + --about-core-values-color: #000; + --about-core-values-shadow: 0 4px 15px 0 rgba(179, 179, 179, 0.2); + --about-team-title-color: #007936; + --about-team-bg: #fff; + --about-team-github-bg: rgba(255, 255, 255, 0.75); + --about-team-shadow: 0 4px 15px 0 rgba(179, 179, 179, 0.2); + --about-team-color: #000; + --about-journey-line-color: #007936; + --about-journey-image-border: #fff; + --about-journey-shadow: 4px -4px 15px 0 rgba(179, 179, 179, 0.25), + 4px 4px 15px 0 rgba(179, 179, 179, 0.25); + --about-journey-dot: url("../assets/about/dot.svg"); + --about-global-impact-image: url("../assets/about/global-impact.svg"); } - @media (min-width: $screen-md) { - h1 { - font-size: 3.5rem; + @if $mode == dark { + --header-next-section-bg: #1b1b1b; + --header-text-primary: #fff; + --header-text-secondary: #b3b3b3; + --header-bg: #101010; + --stats-bg: #000; + --stats-box-shadow: 4px -2px 15px 0 rgba(38, 38, 38, 0.2), + 4px -4px 15px 0 rgba(38, 38, 38, 0.15); + --stats-text-primary: #b3b3b3; + --stats-stat-bg: #394035; + --stats-stat-text: #8ff295; + --boxes-bg: #000; + --boxes-border: #4e4e4e; + --boxes-shadow: none; + --boxes-header-bg-1: #141e34; + --boxes-header-color-1: #9bb6f2; + --boxes-header-bg-2: #321d13; + --boxes-header-color-2: #e3642a; + --boxes-header-bg-3: #343114; + --boxes-header-color-3: #d4c53b; + --boxes-header-bg-4: #341419; + --boxes-header-color-4: #f19ca1; + --boxes-header-bg-5: #1d1434; + --boxes-header-color-5: #bf94ec; + --boxes-main-color: #b3b3b3; + --stairs-color: #8ff295; + --about-bg-primary: #1b1b1b; + --about-bg-secondary: #1b1b1b; + --about-join-us-bg: #000; + --about-join-us-border: 1px solid #4e4e4e; + --about-join-us-color: #b3b3b3; + --about-join-us-image: url("../assets/about/building-dark.svg"); + --about-tablist-border: #858585; + --about-tablist-color: #b3b3b3; + --about-tablist-active-border: #8ff295; + --about-tablist-active-color: #fff; + --about-color: #b3b3b3; + --about-heading-color: #fff; + --about-core-values-bg: #000; + --about-core-values-bg-secondary: #007936; + --about-core-values-color: #fff; + --about-core-values-shadow: 0 4px 15px 0 rgba(179, 179, 179, 0.2); + --about-team-title-color: #8ff295; + --about-team-bg: #000; + --about-team-github-bg: rgba(0, 0, 0, 0.7); + --about-team-shadow: 0 4px 15px 0 rgba(179, 179, 179, 0.2); + --about-team-color: #fff; + --about-journey-line-color: #8ff295; + --about-journey-image-border: #000; + --about-journey-shadow: 4px -4px 15px 0 rgba(179, 179, 179, 0.25), + 4px 4px 15px 0 rgba(179, 179, 179, 0.25); + --about-journey-dot: url("../assets/about/dot-dark.svg"); + --about-global-impact-image: url("../assets/about/global-impact-dark.svg"); + } + } + + h1, + h2, + h3, + h4, + h5, + h6 { + color: var(--about-heading-color); + letter-spacing: 0; + } + + strong { + letter-spacing: 0; + } + + > header { + --header-stats-height: var(--about-stats-height); + @include about.header; + + h1 + p { + font-size: 2rem; + font-weight: 500; + line-height: 120%; + max-width: 43rem; + + @media (max-width: $screen-md) { + font-size: 1.25rem; } } - header { - align-items: center; - display: flex; - flex-direction: column; - gap: 1rem; - padding: 2rem 0; + ul { + @include about.stats; + } + } + + > section { + --center-padding: max( + calc((100vw - var(--max-width)) / 2 + var(--gutter)), + var(--gutter) + ); + @include about.section; - .headline { - font-family: var(--font-heading); - font-size: 1.313rem; - font-style: normal; - font-variation-settings: normal; - font-weight: normal; - line-height: 175%; - margin: 0; + &[aria-labelledby="who_we_are"] { + background: var(--about-bg-secondary); + margin: 0; + max-width: none; + padding: 4rem var(--center-padding); + } + + .tabs { + grid-column: 1 / -1; + padding-top: 2rem; + position: relative; + + .tablist-wrapper { + background: var(--about-bg-secondary); + margin: 0 calc(-1 * var(--center-padding)); + margin-bottom: 2rem; + padding: 0 var(--center-padding); + position: sticky; + top: var(--top-nav-height); + z-index: 2; + } + + .tablist { + border-bottom: 1px solid var(--about-tablist-border); + display: flex; + gap: 3rem; + overflow-x: auto; + + @media (max-width: $screen-md) { + margin-left: calc(-1 * var(--gutter)); + margin-right: calc(-1 * var(--gutter)); + padding: 0 var(--gutter); + } + + a { + color: var(--about-tablist-color); + flex-shrink: 0; + text-decoration: none; + } + + .active { + border-bottom: 2px solid var(--about-tablist-active-border); + color: var(--about-tablist-active-color); + } + } + + > .tabpanel:not(.active) { + display: none !important; } } - p { - font-size: 1rem; - font-weight: 350; - line-height: 175%; + #what_we_offer-panel { + ul { + @include about.boxes; + + @media (min-width: $screen-md) { + gap: 5rem; + } + + @media (min-width: $screen-lg) { + gap: 5rem 8.5rem; + } + + li { + justify-content: flex-start; + } + + @for $i from 1 through 5 { + li:nth-of-type(#{$i}) { + --boxes-header-bg: var(--boxes-header-bg-#{$i}); + --boxes-header-color: var(--boxes-header-color-#{$i}); + } + } + } } - h2 { - font-size: 1.3rem; + #our_journey-panel { + --image-inner-height: calc(720px * 0.45); + --image-border-size: 4px; + --image-height: calc( + var(--image-inner-height) + var(--image-border-size) * 2 + ); + --image-width: calc( + var(--image-inner-height) * 16 / 9 + var(--image-border-size) * 2 + ); + --dot-height: 3rem; + --separator-width: 10rem; + --list-width: calc( + var(--inner-width) - var(--separator-width) - var(--image-width) + ); + + @media (max-width: $screen-xl) { + --separator-width: 6rem; + } + + > p { + margin-bottom: 1rem; + } + + > ul { + border-right: var(--about-journey-line-color) dashed 0.0625rem; + margin-top: 3rem; + width: var(--list-width); + + @media (max-width: $screen-lg) { + border-left: var(--about-journey-line-color) dashed 0.0625rem; + border-right: none; + margin-left: 1rem; + width: auto; + } + + li { + margin: 8rem 0; + min-height: var(--image-height); + padding-right: 2rem; + position: relative; + + &:first-of-type { + margin-top: 2rem; + } + + &:last-of-type { + margin-bottom: 2rem; + } + + @media (max-width: $screen-lg) { + padding-left: 2rem; + } + + &::after { + // dot on vertical dashed line + background-image: var(--about-journey-dot); + background-position: center center; + background-repeat: no-repeat; + content: ""; + display: block; + height: var(--dot-height); + position: absolute; + right: calc(var(--dot-height) / -2); + top: calc(var(--dot-height) / -2); + width: var(--dot-height); + + @media (max-width: $screen-lg) { + --dot-height: 2rem; + left: calc(var(--dot-height) / -2); + right: auto; + } + } + + &:has([id="2017"], [id="20232024"]) { + min-height: 0; + } + } + + h4 { + font-size: 1.375rem; + font-weight: 600; + line-height: 1.5; + margin: 0; + position: relative; + text-decoration-line: underline; + top: -0.75em; + + @media (max-width: $screen-lg) { + font-size: 1.25rem; + margin-bottom: -0.75em; + } + + &::before { + // horizontal line to dot + background: var(--about-journey-line-color); + content: ""; + display: none; + height: 10px; + left: calc(100% + 2rem); + mask-image: url("../assets/about/line-dot.svg"); + mask-position: center right; + mask-repeat: no-repeat; + mask-size: cover; + position: absolute; + top: calc(0.75em - 5px); + width: calc(var(--separator-width) - var(--dot-height) / 2); + + @media (max-width: $screen-lg) { + content: none; + } + } + + ~ p:last-of-type > img { + // image + background-color: var(--about-journey-image-border); + background-position: center center; + background-repeat: no-repeat; + background-size: contain; + border: var(--image-border-size) solid + var(--about-journey-image-border); + box-shadow: var(--about-journey-shadow); + height: var(--image-height); + left: calc(var(--inner-width) - var(--image-width)); + max-width: var(--image-width); + position: absolute; + top: calc(var(--dot-height) / -2); + width: var(--image-width); + + @media (max-width: $screen-lg) { + aspect-ratio: 16 / 9; + box-sizing: content-box; + height: auto; + left: auto; + margin: 2rem auto; + max-height: var(--image-inner-height); + max-width: 100%; + position: relative; + top: auto; + width: auto; + } + } + + &[id="2005"] { + &::before, + ~ p:last-of-type::after { + display: block; + } + } + + &[id="2010"] { + &::before, + ~ p:last-of-type::after { + display: block; + } + } + + &[id="2020"] { + &::before, + ~ p:last-of-type::after { + display: block; + } + } + + &[id="2022"] { + &::before, + ~ p:last-of-type::after { + display: block; + } + } + } + } + + h4 { + font-size: 1.75rem; + font-weight: 600; + } + + mdn-image-history ul { + display: flex; + gap: 1rem; + margin-bottom: -1rem; + overflow-x: auto; + padding-bottom: 1rem; // space for scrollbar + + li { + flex-shrink: 0; + } + + img { + aspect-ratio: 16 / 9; + border: var(--image-border-size) solid + var(--about-journey-image-border); + box-sizing: content-box; + height: calc(720px / 4); + } + } } - .heading-break { - display: none; - @media (min-width: $screen-md) { - display: block; + #our_core_values-panel { + li { + border-radius: 0.5rem; + color: var(--about-core-values-color); + + h4 { + color: var(--about-core-values-color); + font-size: 1rem; + font-weight: 600; + letter-spacing: -0.03125rem; + margin: 0; + margin-bottom: 0.5rem; + } + + &:not(:last-of-type) { + background: var(--about-core-values-bg-secondary); + margin: 1rem auto; + padding: 2rem; + + h4 { + --icon-size: 45px; + align-items: center; + background-position: left center; + background-repeat: no-repeat; + background-size: var(--icon-size) var(--icon-size); + display: flex; + min-height: var(--icon-size); + padding-left: calc(var(--icon-size) + 1rem); + + &#accurate_and_reliable { + background-image: url("../assets/about/accurate-sm.svg"); + } + + &#collaborative_and_community-driven { + background-image: url("../assets/about/collaborative-sm.svg"); + } + + &#inclusive_and_dynamic { + background-image: url("../assets/about/inclusive-sm.svg"); + } + } + } + + &:last-of-type { + background: var(--about-core-values-bg); + margin-top: 2rem; + padding: 2rem; + } + + @media (min-width: $screen-lg) { + display: grid; + grid-auto-flow: dense; + grid-template-columns: [left-start] 40% [left-end right-start] 1fr [right-end]; + padding: 2rem; + + h4 { + font-size: 1.75rem; + margin: 0; + max-width: 70%; + } + + p { + margin-left: var(--gutter); + } + + &:not(:last-of-type) { + background: var(--about-core-values-bg); + margin: 0 auto; + + &:not(:first-of-type) { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + &:not(:nth-last-of-type(2)) { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + + h4 { + --icon-size: 60px; + + align-self: center; + + &#accurate_and_reliable { + background-image: url("../assets/about/accurate.svg"); + } + + &#collaborative_and_community-driven { + background-image: url("../assets/about/collaborative.svg"); + } + + &#inclusive_and_dynamic { + background-image: url("../assets/about/inclusive.svg"); + } + } + + p { + background: var(--about-core-values-bg-secondary); + border-radius: 0.5rem; + padding: 2rem; + } + } + + &:nth-of-type(even):not(:last-of-type) { + h4 { + grid-column: right; + margin: 0 auto; + } + + p { + grid-column: left; + margin-left: 0; + margin-right: var(--gutter); + } + } + + &:last-of-type { + margin-top: 4rem; + } + } + } + } + + #our_team-panel, + #our_partners-panel > div { + --team-grid-gap: 2.5rem; + --team-card-padding: 1.5rem; + + display: grid; + gap: 0 var(--team-grid-gap); + grid-auto-flow: dense; + grid-template-columns: [full-start] 1fr 1fr 1fr [full-end]; + + @media (max-width: $screen-lg) { + --team-grid-gap: 2rem; + grid-template-columns: [full-start] 1fr 1fr [full-end]; + } + + > * { + margin: calc(var(--team-grid-gap) / 2) 0; + scroll-margin-top: calc( + var(--sticky-header-without-actions-height) + 1.5rem + 1rem + ); + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + + > h4, + p { + grid-column: full; + } + + h4, + h5 { + font-size: 1.75rem; + font-weight: 600; + text-transform: none; + + @media (max-width: $screen-md) { + font-size: 1rem; + } + } + + team-member { + align-content: start; + background: var(--about-team-bg); + border: 1px solid var(--about-team-bg); + box-shadow: var(--about-team-shadow); + color: var(--about-team-color); + cursor: pointer; + display: grid; + gap: 0; + grid-row: span 5; + grid-template-areas: + "name" + "title" + "picture" + "bio" + "."; + grid-template-rows: subgrid; + padding: calc(var(--team-card-padding) - 1px); + + @media (max-width: $screen-sm) { + grid-column: full; + } + + &:hover { + border-color: var(--text-inactive); + } + + h4, + h5 { + grid-area: name; + margin: 0; + margin-bottom: 0.5rem; + } + + ul { + display: contents; + } + + li:first-of-type { + color: var(--about-team-title-color); + font-weight: 600; + grid-area: title; + margin-bottom: 0.75rem; + } + + li:nth-of-type(2) { + grid-area: picture; + } + + li:nth-of-type(3):not(:last-of-type) { + align-self: end; + grid-area: picture; + } + + li:last-of-type { + grid-area: bio; + line-height: 1.75; + @include line-clamp(3, 1.75, var(--about-team-bg)); + } + + img { + aspect-ratio: 1; + margin-bottom: 0.75rem; + width: 100%; + } + + a[href^="https://github.com"] + { + background: var(--about-team-github-bg); + border-top-right-radius: 0.5rem; + color: var(--about-team-color); + margin-top: -2.9rem; + padding: 0.25rem 0.5rem; + padding-right: 0.7rem; + position: absolute; + + &::before { + background: var(--about-team-color); + content: ""; + display: inline-block; + height: 1.2em; + margin-bottom: 0.2em; + margin-right: 0.2em; + mask-image: url("../assets/icons/github-mark-small.svg"); + mask-repeat: no-repeat; + vertical-align: middle; + width: 1.2em; + } + } + + &:focus-within { + align-content: start; + cursor: unset; + display: grid; + gap: 0 var(--team-card-padding); + grid-column: span 2; + grid-template-areas: + "name name" + "title title" + "picture bio" + ". bio" + ". bio"; + grid-template-columns: + calc( + (100% - var(--team-grid-gap) - 2 * var(--team-card-padding)) / 2 + ) + 1fr; + + li:last-of-type { + max-height: unset; + + &::after { + display: none; + } + } + + @media (max-width: $screen-sm) { + grid-template-areas: + "name" + "title" + "picture" + "bio"; + grid-template-columns: 1fr; + + ul li:nth-of-type(3):not(:last-of-type) { + align-self: end; + grid-area: picture; + + a { + position: absolute; + } + } + } + } + } + } + + #our_partners-panel > div { + margin-top: 2.5rem; + } + + &[aria-labelledby="global_impact"] { + display: block; + margin: var(--about-section-gap) auto; + + @media (min-width: $screen-lg) { + .section-content { + background: var(--about-global-impact-image); + background-position: right; + background-repeat: no-repeat; + background-size: 20rem 100%; + padding-right: 30rem; + } + } + + ul { + margin-top: 1rem; + @include about.stairs; + + li:nth-child(1) { + --stairs-icon: url("../assets/about/education.svg"); + } + + li:nth-child(2) { + --stairs-icon: url("../assets/about/text-box-check-outline.svg"); + } + + li:nth-child(3) { + --stairs-icon: url("../assets/about/web-check.svg"); + } + + li:nth-child(4) { + --stairs-icon: url("../assets/about/handshake.svg"); + } + } + } + + &[aria-labelledby="join_us_in_building_a_better_web"] { + background: var(--about-join-us-image) var(--about-join-us-bg); + background-position: 1.5rem; + background-repeat: no-repeat; + background-size: 20rem calc(100% - 3rem); + border: var(--about-join-us-border); + border-radius: 0.5rem; + color: var(--about-join-us-color); + display: flex; + flex-direction: column; + justify-content: center; + margin-bottom: var(--about-section-gap); + max-width: calc(100% - 2 * var(--center-padding)); + padding: 4rem 1rem; + padding-left: min(30rem, 50%); + + @media (max-width: $screen-md) { + background-color: transparent; + background-position: center bottom; + background-size: 100% 10rem; + border: none; + padding: 1rem 0; + padding-bottom: 12rem; } } } diff --git a/client/src/about/index.tsx b/client/src/about/index.tsx index 760c7bc0d3d5..92055d8c82f2 100644 --- a/client/src/about/index.tsx +++ b/client/src/about/index.tsx @@ -1,74 +1,201 @@ -import { useLocale } from "../hooks"; -import { GetInvolved } from "../ui/molecules/get_involved"; +import { HydrationData } from "../../../libs/types/hydration"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { ProseSection } from "../../../libs/types/document"; +import useSWR from "swr"; +import { HTTPError } from "../document"; +import { WRITER_MODE } from "../env"; +import { Prose } from "../document/ingredients/prose"; + import "./index.scss"; +import "./custom-elements"; +import { useGleanClick } from "../telemetry/glean-context"; +import { ABOUT } from "../telemetry/constants"; + +export interface AboutSection extends ProseSection { + H3s?: AboutSection[]; +} + +export interface AboutDoc { + title: string; + sections: AboutSection[]; +} + +export function About(appProps: HydrationData) { + const doc = useAboutDoc(appProps); -export function About() { - const locale = useLocale(); return ( -
-
-

Build it better

-

- MDN Web Docs is an open-source, collaborative project documenting Web - platform technologies, including{" "} - CSS,{" "} - HTML,{" "} - JavaScript, and{" "} - Web APIs. We also provide an - extensive set of{" "} - learning resources for beginning - developers and students. -

+
+ { + if (i === 0) { + return
; + } else if (section.H3s) { + return ; + } + return null; + }} + /> +
+ ); +} + +export function useAboutDoc( + appProps?: HydrationData +): AboutDoc | undefined { + const { data } = useSWR( + "index.json", + async () => { + const url = new URL( + `${window.location.pathname.replace(/\/$/, "")}/index.json`, + window.location.origin + ).toString(); + const response = await fetch(url); + + if (!response.ok) { + switch (response.status) { + case 404: + throw new HTTPError(response.status, url, "Page not found"); + } + + const text = await response.text(); + throw new HTTPError(response.status, url, text); + } + + return (await response.json())?.hyData; + }, + { + fallbackData: appProps?.hyData, + revalidateOnFocus: WRITER_MODE, + revalidateOnMount: true, + } + ); + const doc: AboutDoc | undefined = data || appProps?.hyData || undefined; + return doc; +} + +function RenderAboutBody({ + doc, + renderer = () => null, +}: { + doc?: AboutDoc; + renderer?: (section: AboutSection, i: number) => null | JSX.Element; +}) { + const sections = Array.from(doc?.sections || []).reduce( + (acc, curr) => { + if (curr.value.isH3) { + const prev = acc.at(-1); + if (prev) { + prev.H3s ? prev.H3s.push(curr) : (prev.H3s = [curr]); + } + } else { + acc.push(Object.assign({}, curr)); + } + return acc; + }, + [] + ); + return sections.map((section, i) => { + return ( + renderer(section, i) || ( + + ) + ); + }); +} + +export function Header({ section }: { section: AboutSection }) { + return section.value.content ? ( +
+
+
+ ) : null; +} + +function Tabs({ section }: { section: AboutSection }) { + const [activeTab, setActiveTab] = useState(0); + const tabs = useRef(null); + const gleanClick = useGleanClick(); + + const changeTab = useCallback( + (i: number) => { + const id = section.H3s?.[i].value.id; + if (id) { + setActiveTab(i); + if (tabs.current && tabs.current.getBoundingClientRect().top < 0) { + tabs.current.scrollIntoView({ block: "start", inline: "nearest" }); + } + gleanClick(`${ABOUT}: tab -> ${id}`); + } + }, + [section.H3s, gleanClick] + ); + + useEffect(() => { + const hash = document.location.hash.startsWith("#our_team") + ? "#our_team" + : document.location.hash.startsWith("#our_partners") || + document.location.hash === "#pab" || + document.location.hash === "#owd" + ? "#our_partners" + : document.location.hash; + const tab = section.H3s?.findIndex(({ value }) => `#${value.id}` === hash); + if (tab && tab > 0) { + setActiveTab(tab); + } + }, [section.H3s, changeTab]); -
- - - MDN's mission is to{" "} - provide a blueprint for a better internet and empower a new - generation of developers and content creators to build it. - - -
-

- We're always striving to connect developers more seamlessly with the - tools and information they need to easily build projects on the{" "} - open Web. Since our beginnings in 2005, Mozilla and - the community have amassed around 45,000 pages of free, open-source - content. -

- {/**/} -

- Independent and unbiased - across browsers and technologies -

-

- This guiding principle has made MDN Web Docs the go-to repository of - independent information for developers, regardless of brand, browser - or platform. We are an open community of devs, writers, and other - technologists building resources for a better Web, with over 17 - million monthly MDN users from all over the world. Anyone can - contribute, and each of the 45,000 individuals who have done so over - the past decades has strengthened and improved the resource. We also - receive content contributions from our partners, including Microsoft, - Google, Samsung, Igalia, W3C and others. Together we continue to drive - innovation on the Web and serve the common good. -

-

Accurate and vetted for quality

-

- Through our GitHub documentation repository, contributors can make - changes, submit pull requests, have their contributions reviewed and - then merged with existing content. Through{" "} - - this workflow - - , we welcome the vast knowledge and experience of our developer - community while maintaining a high level of quality, accurate content. -

-
- -
+ return ( + section.value.id && + section.value.content && ( +
+

{section.value.title}

+
+ {section.H3s && ( +
+
+
+ {section.H3s?.map( + ({ value }, i) => + value.id && + value.content && ( + changeTab(i)} + > + {value.title} + + ) + )} +
+
+ {section.H3s?.map( + ({ value }, i) => + value.id && + value.content && ( +
+ ) + )} +
+ )} +
+ ) ); } diff --git a/client/src/about/testimonial/index.scss b/client/src/about/testimonial/index.scss deleted file mode 100644 index 2a245a2bb3e9..000000000000 --- a/client/src/about/testimonial/index.scss +++ /dev/null @@ -1,64 +0,0 @@ -@use "../../ui/vars" as *; - -.testimonial { - display: flex; - flex-direction: column; - gap: 2rem; - padding: 2rem 0; - width: 100%; - - @media (min-width: $screen-md) { - flex-direction: row; - } - - iframe { - height: 50vw; - padding: 0; - - @media (min-width: $screen-md) { - height: initial; - width: 48%; - } - } - - .testimonial-copy { - margin: 0 auto; - max-width: 18rem; - text-align: center; - - @media (min-width: $screen-md) { - margin: initial; - text-align: initial; - } - - img { - margin: 0 auto; - - @media (min-width: $screen-md) { - margin: initial; - } - } - - p { - font-size: 18px; - line-height: 120%; - } - - .author-name, - .author-title { - display: block; - /* MDN UI / Body / M */ - font-size: 13px; - line-height: 1.2; - } - } - - .quotation-mark { - background-color: var(--icon-primary); - height: 10px; - margin-left: 4px; - mask-image: url("./quote.svg"); - mask-size: cover; - width: 10px; - } -} diff --git a/client/src/about/testimonial/index.tsx b/client/src/about/testimonial/index.tsx deleted file mode 100644 index 9d0695f0ee92..000000000000 --- a/client/src/about/testimonial/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import "./index.scss"; -import { ReactComponent as Quote } from "./quote.svg"; - -export function Testimonial() { - return ( -
- -
- -

- Condimentum donec quam odio viverra erat mi mae-cenas odio. Tempus - arcu tincidunt tortor placerat tempor pharetra. -

- - First Name - - Title goes here -
-
- ); -} diff --git a/client/src/about/testimonial/quote.svg b/client/src/about/testimonial/quote.svg deleted file mode 100644 index 19dcfe170995..000000000000 --- a/client/src/about/testimonial/quote.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/src/app.scss b/client/src/app.scss index eb5427c31dbf..6281566b0080 100644 --- a/client/src/app.scss +++ b/client/src/app.scss @@ -157,7 +157,6 @@ main { min-height: 80vh; } -.about-container, .main-page-content { a { &:link, diff --git a/client/src/app.tsx b/client/src/app.tsx index 001c73bba834..e452d6c89a3f 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -322,7 +322,7 @@ export function App(appProps: HydrationData) { path="/about/*" element={ - + } /> diff --git a/client/src/assets/about/accurate-sm.svg b/client/src/assets/about/accurate-sm.svg new file mode 100644 index 000000000000..1bfb970504aa --- /dev/null +++ b/client/src/assets/about/accurate-sm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/accurate.svg b/client/src/assets/about/accurate.svg new file mode 100644 index 000000000000..a8fc0113c5ea --- /dev/null +++ b/client/src/assets/about/accurate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/building-dark.svg b/client/src/assets/about/building-dark.svg new file mode 100644 index 000000000000..76e77083c4d1 --- /dev/null +++ b/client/src/assets/about/building-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/building.svg b/client/src/assets/about/building.svg new file mode 100644 index 000000000000..848d7e6395b6 --- /dev/null +++ b/client/src/assets/about/building.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/collaborative-sm.svg b/client/src/assets/about/collaborative-sm.svg new file mode 100644 index 000000000000..09cbf91b4ea6 --- /dev/null +++ b/client/src/assets/about/collaborative-sm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/collaborative.svg b/client/src/assets/about/collaborative.svg new file mode 100644 index 000000000000..56b62cce0fd3 --- /dev/null +++ b/client/src/assets/about/collaborative.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/dot-dark.svg b/client/src/assets/about/dot-dark.svg new file mode 100644 index 000000000000..15aed46ddf1a --- /dev/null +++ b/client/src/assets/about/dot-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/dot.svg b/client/src/assets/about/dot.svg new file mode 100644 index 000000000000..9af28548b671 --- /dev/null +++ b/client/src/assets/about/dot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/education.svg b/client/src/assets/about/education.svg new file mode 100644 index 000000000000..8d4393d8497a --- /dev/null +++ b/client/src/assets/about/education.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/global-impact-dark.svg b/client/src/assets/about/global-impact-dark.svg new file mode 100644 index 000000000000..f51d35856b88 --- /dev/null +++ b/client/src/assets/about/global-impact-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/global-impact.svg b/client/src/assets/about/global-impact.svg new file mode 100644 index 000000000000..96c6848942b1 --- /dev/null +++ b/client/src/assets/about/global-impact.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/handshake.svg b/client/src/assets/about/handshake.svg new file mode 100644 index 000000000000..680d0ee30401 --- /dev/null +++ b/client/src/assets/about/handshake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/inclusive-sm.svg b/client/src/assets/about/inclusive-sm.svg new file mode 100644 index 000000000000..d85a3e471d74 --- /dev/null +++ b/client/src/assets/about/inclusive-sm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/inclusive.svg b/client/src/assets/about/inclusive.svg new file mode 100644 index 000000000000..db690b38296d --- /dev/null +++ b/client/src/assets/about/inclusive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/line-dot.svg b/client/src/assets/about/line-dot.svg new file mode 100644 index 000000000000..894138b85160 --- /dev/null +++ b/client/src/assets/about/line-dot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/sparkle.svg b/client/src/assets/about/sparkle.svg new file mode 100644 index 000000000000..87bdd6cb9b55 --- /dev/null +++ b/client/src/assets/about/sparkle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/text-box-check-outline.svg b/client/src/assets/about/text-box-check-outline.svg new file mode 100644 index 000000000000..af670b7d9c92 --- /dev/null +++ b/client/src/assets/about/text-box-check-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/about/web-check.svg b/client/src/assets/about/web-check.svg new file mode 100644 index 000000000000..2d5f0e3c2e0e --- /dev/null +++ b/client/src/assets/about/web-check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/lines.svg b/client/src/assets/lines.svg new file mode 100644 index 000000000000..20189e58c466 --- /dev/null +++ b/client/src/assets/lines.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/community/index.scss b/client/src/community/index.scss index e82e3e6b4645..e73d9749105f 100644 --- a/client/src/community/index.scss +++ b/client/src/community/index.scss @@ -1,5 +1,6 @@ @use "../ui/vars" as *; @use "../ui/atoms/button/mixins" as button; +@use "../about/mixins" as about; @mixin light-theme { --community-bg-primary: #fcfcfc; @@ -76,71 +77,22 @@ main.community-container { --community-stats-height: 5.75rem; --community-section-gap: 5rem; --max-width: 74rem; - --negative-space: calc( - max(0px, 100vw - var(--max-width)) * -0.5 - var(--gutter) - ); + --layout-text-primary: var(--community-text-primary); background: var(--community-bg-secondary); color: var(--community-text-secondary); - h2, - h3, - p { - margin: 0; - } - - h2, - h3 { - color: var(--community-text-primary); - - a { - color: unset; - text-decoration: none; - } - } - - a { - text-decoration: underline; - - &:hover { - text-decoration: none; - } - } - - p + p { - margin-top: 1.5rem; - } - - section { - margin-left: auto; - margin-right: auto; - max-width: var(--max-width); - padding-left: var(--gutter); - padding-right: var(--gutter); - width: 100%; - } - - h2 { - font-size: 2rem; - font-weight: 600; - margin-bottom: 1rem; - - @media (max-width: $screen-md) { - font-size: 1.375rem; - } - } + @include about.layout; > header { - background: linear-gradient( - to top, - transparent 0%, - transparent calc(var(--community-stats-height) / 2), - var(--community-bg-primary) calc(var(--community-stats-height) / 2), - var(--community-bg-primary) 100% - ); + --header-text-primary: var(--community-text-primary); + --header-text-secondary: var(--community-header-text); + --header-stats-height: var(--community-stats-height); + --header-bg: var(--community-bg-primary); + + @include about.header; @media (max-width: $screen-md) { - padding-top: 1rem; text-align: center; } @@ -150,7 +102,6 @@ main.community-container { right; background-repeat: no-repeat; background-size: 50%; - padding-top: var(--community-section-gap); @media (max-width: $screen-md) { background-position: top center; @@ -159,21 +110,6 @@ main.community-container { } } - h1 { - color: var(--community-text-primary); - font-size: 2.5rem; - margin-bottom: 1rem; - - @media (max-width: $screen-md) { - font-size: 2rem; - } - } - - p { - color: var(--community-header-text); - margin-bottom: 1.5rem; - } - ul:first-of-type { display: flex; flex-wrap: wrap; @@ -194,73 +130,24 @@ main.community-container { } ul:last-of-type { - background: var(--community-card-bg); - border-radius: 0.5rem; - box-shadow: var(--community-box-shadow); - color: var(--community-text-primary); - display: flex; - gap: 1rem; - justify-content: space-around; - margin-top: var(--community-section-gap); - padding: 1rem; - - @media (max-width: $screen-md) { - flex-wrap: wrap; - margin-top: 2rem; - } - - li { - align-items: baseline; - column-gap: 1rem; - display: flex; - flex-wrap: wrap; - justify-content: center; - min-width: 7.75rem; - overflow-wrap: anywhere; - - @media (max-width: $screen-md) { - align-items: center; - flex: 1; - flex-direction: column; - justify-content: flex-start; - } - - strong { - align-items: center; - background: var(--community-header-stats-bg); - border-radius: 50%; - color: var(--community-text-success); - display: inline-flex; - height: 3.75rem; - justify-content: center; - width: 3.75rem; - } - } - } - } + --stats-bg: var(--community-card-bg); + --stats-box-shadow: var(--community-box-shadow); + --stats-text-primary: var(--community-text-primary); + --stats-stat-bg: var(--community-header-stats-bg); + --stats-stat-text: var(--community-text-success); - > header + section { - margin-top: 4.56rem; - - @media (max-width: $screen-md) { - margin-top: 2rem; + @include about.stats; } } > section { --community-circle-height: 57rem; - column-gap: min(5rem, 5vw); - display: grid; - grid-template-columns: 4fr 6fr; + + @include about.section; @media (max-width: $screen-md) { /* stylelint-disable-next-line length-zero-no-unit */ --community-circle-height: 0rem; - display: block; - } - - > * { - min-width: 0; } &[aria-labelledby="meet_our_contributors"] { @@ -492,6 +379,7 @@ main.community-container { &[aria-labelledby="join_us_in_shaping_a_better_web"] { display: block; + margin-bottom: var(--community-section-gap); margin-top: var(--community-section-gap); p { @@ -499,43 +387,16 @@ main.community-container { } ul { - display: grid; - gap: 2rem; - grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); - margin-bottom: var(--community-section-gap); - } + --boxes-bg: var(--community-card-bg); + --boxes-border: var(--community-card-border); + --boxes-shadow: var(--community-box-shadow); + --boxes-header-bg: var(--community-card-header-bg); - li { - align-items: center; - background: var(--community-card-bg); - border: 1px solid var(--community-card-border); - border-radius: 0.5rem; - box-shadow: var(--community-box-shadow); - display: flex; - flex-direction: column; - gap: 1.5rem; - justify-content: space-between; - padding: 1.5rem; - text-align: center; - - h3 { - align-self: stretch; - background: var(--community-card-header-bg); - border-radius: 0.5rem 0.5rem 0 0; - font-size: 1.25rem; - font-weight: 500; - margin: -1.5rem; - margin-bottom: 0; - padding: 1.5rem; - } - - p { - margin: 0; - } + @include about.boxes; + } - a { - @include button.primary; - } + li a { + @include button.primary; } } diff --git a/client/src/community/index.tsx b/client/src/community/index.tsx index 26b9e6526f81..e2290d123a52 100644 --- a/client/src/community/index.tsx +++ b/client/src/community/index.tsx @@ -1,21 +1,14 @@ import "./index.scss"; import { HydrationData } from "../../../libs/types/hydration"; -import { useEffect, useMemo } from "react"; -import { Section } from "../../../libs/types/document"; +import { useEffect } from "react"; import useSWR, { SWRConfig } from "swr"; -import { HTTPError } from "../document"; -import { WRITER_MODE } from "../env"; import { Prose } from "../document/ingredients/prose"; import { SWRLocalStorageCache } from "../utils"; import { useIsServer } from "../hooks"; +import { AboutDoc, AboutSection, Header, useAboutDoc } from "../about"; -interface CommunityDoc { - title: string; - sections: Section[]; -} - -export function Community(appProps: HydrationData) { - const doc = useCommunityDoc(appProps); +export function Community(appProps: HydrationData) { + const doc = useAboutDoc(appProps); useEffect(() => { import("./contributor-list"); @@ -25,18 +18,12 @@ export function Community(appProps: HydrationData) { new SWRLocalStorageCache("community") }} > -
+
{ if (i === 0) { - return ( -
- ); + return
; } else if (section.value.id === "help_us_fix_open_issues") { return ; } @@ -48,46 +35,12 @@ export function Community(appProps: HydrationData) { ); } -function useCommunityDoc( - appProps?: HydrationData -): CommunityDoc | undefined { - const { data } = useSWR( - "index.json", - async () => { - const url = new URL( - `${window.location.pathname.replace(/\/$/, "")}/index.json`, - window.location.origin - ).toString(); - const response = await fetch(url); - - if (!response.ok) { - switch (response.status) { - case 404: - throw new HTTPError(response.status, url, "Page not found"); - } - - const text = await response.text(); - throw new HTTPError(response.status, url, text); - } - - return (await response.json())?.hyData; - }, - { - fallbackData: appProps?.hyData, - revalidateOnFocus: WRITER_MODE, - revalidateOnMount: true, - } - ); - const doc: CommunityDoc | undefined = data || appProps?.hyData || undefined; - return doc; -} - function RenderCommunityBody({ doc, renderer = () => null, }: { - doc?: CommunityDoc; - renderer?: (section: Section, i: number) => null | JSX.Element; + doc?: AboutDoc; + renderer?: (section: AboutSection, i: number) => null | JSX.Element; }) { return doc?.sections.map((section, i) => { return ( @@ -98,23 +51,7 @@ function RenderCommunityBody({ }); } -function Header({ section, h1 }: { section: any; h1?: string }) { - const html = useMemo( - () => ({ __html: section.value?.content }), - [section.value?.content] - ); - return ( -
-
-
- ); -} - -function Issues({ section }: { section: any }) { - const html = useMemo( - () => ({ __html: section.value?.content }), - [section.value?.content] - ); +function Issues({ section }: { section: AboutSection }) { const isServer = useIsServer(); const LABELS = ["good first issue", "accepting PR"]; const { data } = useSWR( @@ -134,10 +71,13 @@ function Issues({ section }: { section: any }) { revalidateOnFocus: false, } ); - return ( + return section.value.id && section.value.content ? (

{section.value.title}

-
+
@@ -184,5 +124,5 @@ function Issues({ section }: { section: any }) {
- ); + ) : null; } diff --git a/client/src/telemetry/constants.ts b/client/src/telemetry/constants.ts index 1f6735dd726a..c2942fe6f269 100644 --- a/client/src/telemetry/constants.ts +++ b/client/src/telemetry/constants.ts @@ -29,6 +29,7 @@ export const SETTINGS = "settings"; export const OBSERVATORY = "observatory"; export const CURRICULUM = "curriculum"; export const BCD_TABLE = "bcd"; +export const ABOUT = "about"; export const A11Y_MENU = "a11y_menu"; diff --git a/libs/constants/index.js b/libs/constants/index.js index 8b0da8d3aea8..7dda3d74fac1 100644 --- a/libs/constants/index.js +++ b/libs/constants/index.js @@ -164,6 +164,7 @@ export const CSP_DIRECTIVES = { // Shared assets. "https://mdn.github.io/shared-assets/", + "https://mdn.dev/", // GA4. "https://*.google-analytics.com", From 3e781a096f76db4efd7237458a7ab41dcf3fdd8b Mon Sep 17 00:00:00 2001 From: Hak Lee Date: Fri, 6 Dec 2024 23:16:10 +0900 Subject: [PATCH 5/5] fix(i10n): localize secureContext header and inline text in ko (#12183) * docs(ko): translate secure context inline to Korean * docs(ko): translate secure context header to Korean --- kumascript/macros/secureContext_header.ejs | 2 ++ kumascript/macros/secureContext_inline.ejs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/kumascript/macros/secureContext_header.ejs b/kumascript/macros/secureContext_header.ejs index 95095e5ce388..2476bd905daf 100644 --- a/kumascript/macros/secureContext_header.ejs +++ b/kumascript/macros/secureContext_header.ejs @@ -11,6 +11,7 @@ var str_title = mdn.localString({ "es" : "Contexto seguro", "fr" : "Contexte sécurisé", "ja" : "安全なコンテキスト用", + "ko" : "보안 컨텍스트", "zh-CN": "安全上下文" }); @@ -20,6 +21,7 @@ var str_desc = mdn.localString({ "es" : "Esta función está disponible solo en contextos seguros (HTTPS), en algunos o todos los navegadores que lo soportan.", "fr" : "Cette fonctionnalité est uniquement disponible dans des contextes sécurisés (HTTPS), pour certains navigateurs qui la prennent en charge.", "ja" : "この機能は一部またはすべての対応しているブラウザーにおいて、安全なコンテキスト (HTTPS) でのみ利用できます。", + "ko" : "이 기능은 일부 또는 모든 지원 브라우저보안 컨텍스트 (HTTPS)에서만 사용할 수 있습니다.", "zh-CN": "此项功能仅在一些支持的浏览器安全上下文(HTTPS)中可用。" }); diff --git a/kumascript/macros/secureContext_inline.ejs b/kumascript/macros/secureContext_inline.ejs index 14826363b45e..dfcbf0c24840 100644 --- a/kumascript/macros/secureContext_inline.ejs +++ b/kumascript/macros/secureContext_inline.ejs @@ -8,6 +8,7 @@ var str_title = mdn.localString({ "es" : "Contexto seguro", "fr" : "Contexte sécurisé", "ja" : "安全なコンテキスト用", + "ko" : "보안 컨텍스트", "zh-CN": "安全上下文" }); @@ -16,6 +17,7 @@ var str_tooltip = mdn.localString({ "es" : "Esta función está disponible solo en contextos seguros (HTTPS)", "fr" : "Cette fonctionnalité est uniquement disponible dans des contextes sécurisés (HTTPS)", "ja" : "この機能は安全なコンテキスト (HTTPS) でのみ利用できます", + "ko" : "이 기능은 보안 컨텍스트 (HTTPS)에서만 사용할 수 있습니다", "zh-CN": "此功能仅在安全上下文(HTTPS)中可用" }); %>