mirror of
https://github.com/meshtastic/meshtastic.git
synced 2025-01-26 05:01:38 -08:00
Initial FAQ setup with structured data
structured data auto expand working with url better url handling for preexpand support multiple but not quite real multi support
This commit is contained in:
parent
e674eba6c1
commit
1a5a0c7ded
|
@ -5,39 +5,51 @@ slug: /faq
|
|||
sidebar_position: 3
|
||||
---
|
||||
|
||||
## Overview
|
||||
import { FaqAccordion } from "/src/components/FaqAccordion";
|
||||
|
||||
### Where can I get additional help, ask questions, or bond with the Meshtastic community?
|
||||
|
||||
This site (which has a great search function) is the preferred place for up-to-date documentation. Many of our users and developers hang out on the [Meshtastic Discord](https://discord.gg/ktMAKGBnBs) server where you may connect with like-minded people.
|
||||
|
||||
### How can I contribute to Meshtastic?
|
||||
|
||||
Everyone contributes in a different way. Join the [Meshtastic Discord](https://discord.gg/ktMAKGBnBs) and introduce yourself. We're all very friendly. If you'd like to pitch in some code, check out the [Development](/docs/developers) menu on the left.
|
||||
|
||||
<!-- Android Client-->
|
||||
|
||||
## Android Client
|
||||
|
||||
### What versions of Android does the Meshtastic Android App require?
|
||||
|
||||
Minimum requirement is Android 5 (Lollipop 2014, first BLE support), however at least Android 6 (Marshmallow 2015) is recommended as Bluetooth is more stable. While Android 5/6 are officially supported by Meshtastic, it is _not_ recommended that you purchase devices with these versions due to their limited OS support and limited battery life due to age. Many newer models exist that are very affordable. A good resource to use when researching affordable devices is the [LineageOS Supported Devices List](https://wiki.lineageos.org/devices/).
|
||||
|
||||
### What does the icon next to the message mean?
|
||||
export const GeneralFaq = [
|
||||
{
|
||||
title: "Where can I get additional help, ask questions, or bond with the Meshtastic community?",
|
||||
content: `This site (which has a great search function) is the preferred place for up-to-date documentation. Many of our users and developers hang out on the [Meshtastic Discord](https://discord.gg/ktMAKGBnBs) server where you may connect with like-minded people.`,
|
||||
},
|
||||
{
|
||||
title: "How can I contribute to Meshtastic?",
|
||||
content: "Everyone contributes in a different way. Join the [Meshtastic Discord](https://discord.gg/ktMAKGBnBs) and introduce yourself. We're all very friendly. If you'd like to pitch in some code, check out the [Development](/docs/developers) menu on the left.",
|
||||
},
|
||||
];
|
||||
|
||||
export const AndroidFaq = [
|
||||
{
|
||||
title: "What versions of Android does the Meshtastic Android App require?",
|
||||
content: `Minimum requirement is Android 5 (Lollipop 2014, first BLE support), however at least Android 6 (Marshmallow 2015) is recommended as Bluetooth is more stable. While Android 5/6 are officially supported by Meshtastic, it is _not_ recommended that you purchase devices with these versions due to their limited OS support and limited battery life due to age. Many newer models exist that are very affordable. A good resource to use when researching affordable devices is the [LineageOS Supported Devices List](https://wiki.lineageos.org/devices/).`,
|
||||
},
|
||||
{
|
||||
title: "What does the icon next to the message mean?",
|
||||
content: `
|
||||
- Cloud with an up arrow - Queued on the app to be sent to your device.
|
||||
- Cloud only - Queued on the device to be sent over the mesh.
|
||||
- Cloud with a check mark - At least one other node on the mesh acknowledged the message.
|
||||
- Person with a check mark - The intended recipient of your direct message acknowledged the message.
|
||||
- Cloud crossed out - Not acknowledged or message error.
|
||||
- Cloud crossed out - Not acknowledged or message error.`,
|
||||
},
|
||||
{
|
||||
title: "How can I clear the message history?",
|
||||
content: `Long press any message to select and show the menu with "delete" and "select all" buttons.`,
|
||||
},
|
||||
{
|
||||
title: "After a fresh firmware install, my node is not connecting via Bluetooth. What should I do?",
|
||||
content: `Try forgetting the Bluetooth connection from the Android Bluetooth Settings menu. Re-pair and try again. This is a security measure and there is no workaround for it. It prevents apps and other accessories from spoofing an existing accessory by un-pairing and "re-pairing" themselves without the users' knowledge.`,
|
||||
},
|
||||
];
|
||||
|
||||
### How can I clear the message history?
|
||||
## Overview
|
||||
|
||||
Long press any message to select and show the menu with "delete" and "select all" buttons.
|
||||
<FaqAccordion rows={GeneralFaq} slug="general" />
|
||||
|
||||
### After a fresh firmware install, my node is not connecting via Bluetooth. What should I do?
|
||||
<!-- Android Client-->
|
||||
|
||||
Try forgetting the Bluetooth connection from the Android Bluetooth Settings menu. Re-pair and try again. This is a security measure and there is no workaround for it. It prevents apps and other accessories from spoofing an existing accessory by un-pairing and "re-pairing" themselves without the users' knowledge.
|
||||
## Android Client
|
||||
<FaqAccordion rows={AndroidFaq} slug="android" />
|
||||
|
||||
<!-- Apple Clients-->
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
"dotenv": "^16.3.1",
|
||||
"postcss": "^8.4.33",
|
||||
"react": "^18.2.0",
|
||||
"react-accessible-accordion": "^5.0.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"remark-deflist": "^1.0.0",
|
||||
"swr": "^2.2.4",
|
||||
"tailwindcss": "^3.4.1"
|
||||
|
|
|
@ -50,12 +50,18 @@ dependencies:
|
|||
react:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0
|
||||
react-accessible-accordion:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0(react-dom@18.2.0)(react@18.2.0)
|
||||
react-dom:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
react-icons:
|
||||
specifier: ^4.12.0
|
||||
version: 4.12.0(react@18.2.0)
|
||||
react-markdown:
|
||||
specifier: ^9.0.1
|
||||
version: 9.0.1(@types/react@18.2.47)(react@18.2.0)
|
||||
remark-deflist:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
|
@ -5793,6 +5799,10 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/html-url-attributes@3.0.0:
|
||||
resolution: {integrity: sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==}
|
||||
dev: false
|
||||
|
||||
/html-void-elements@3.0.0:
|
||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||
dev: false
|
||||
|
@ -8413,6 +8423,16 @@ packages:
|
|||
strip-json-comments: 2.0.1
|
||||
dev: false
|
||||
|
||||
/react-accessible-accordion@5.0.0(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-MT2obYpTgLIIfPr9d7hEyvPB5rg8uJcHpgA83JSRlEUHvzH48+8HJPvzSs+nM+XprTugDgLfhozO5qyJpBvYRQ==}
|
||||
peerDependencies:
|
||||
react: ^16.3.2 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.3.3 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react-dev-utils@12.0.1(typescript@5.3.3)(webpack@5.89.0):
|
||||
resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
@ -8529,6 +8549,28 @@ packages:
|
|||
webpack: 5.89.0
|
||||
dev: false
|
||||
|
||||
/react-markdown@9.0.1(@types/react@18.2.47)(react@18.2.0):
|
||||
resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==}
|
||||
peerDependencies:
|
||||
'@types/react': '>=18'
|
||||
react: '>=18'
|
||||
dependencies:
|
||||
'@types/hast': 3.0.3
|
||||
'@types/react': 18.2.47
|
||||
devlop: 1.1.0
|
||||
hast-util-to-jsx-runtime: 2.3.0
|
||||
html-url-attributes: 3.0.0
|
||||
mdast-util-to-hast: 13.0.2
|
||||
react: 18.2.0
|
||||
remark-parse: 11.0.0
|
||||
remark-rehype: 11.0.0
|
||||
unified: 11.0.4
|
||||
unist-util-visit: 5.0.0
|
||||
vfile: 6.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/react-router-config@5.1.1(react-router@5.3.4)(react@18.2.0):
|
||||
resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==}
|
||||
peerDependencies:
|
||||
|
|
99
src/components/FaqAccordion.tsx
Normal file
99
src/components/FaqAccordion.tsx
Normal file
|
@ -0,0 +1,99 @@
|
|||
import React from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
AccordionItemHeading,
|
||||
AccordionItemButton,
|
||||
AccordionItemPanel,
|
||||
} from "react-accessible-accordion";
|
||||
import "react-accessible-accordion/dist/fancy-example.css";
|
||||
|
||||
export interface Faq {
|
||||
title: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the query parameter `openFaqItems` which is an array of
|
||||
* faq items that should be pre-opened
|
||||
* @type {Function}
|
||||
*/
|
||||
const getOpenFaqItemsFromUrl = (slug: String): string[] => {
|
||||
// Use URLSearchParams to parse the query parameters from the current URL
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// Get the 'openFaqItems' parameter as a comma-separated string
|
||||
const openFaqItemsString = searchParams.get(`openFaqItems-${slug}`);
|
||||
|
||||
// If the parameter exists, split it by commas into an array; otherwise, return an empty array
|
||||
return openFaqItemsString ? openFaqItemsString.split(',') : [];
|
||||
};
|
||||
|
||||
export const FaqAccordion = ({
|
||||
rows,
|
||||
slug
|
||||
}: { rows: Faq[], slug: String }): JSX.Element => {
|
||||
// Set the faq structured data
|
||||
const faqStructuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
mainEntity: rows.map((row) => ({
|
||||
"@type": "Question",
|
||||
name: row.title,
|
||||
acceptedAnswer: {
|
||||
"@type": "Answer",
|
||||
text: row.content,
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
// Use the getOpenFaqItemsFromUrl function to set the
|
||||
// initial state of preExpanded based on URL parameters
|
||||
const [preExpanded, setPreExpanded] = React.useState<string[]>(getOpenFaqItemsFromUrl(slug));
|
||||
|
||||
/**
|
||||
* Updates query parameters in the url when items are opened
|
||||
* so that a link can be shared with the faq item already opened
|
||||
*/
|
||||
const handleChange = (openFaqItems: (string | number)[]): void => {
|
||||
// Get current url params
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// Convert openFaqItems to a comma-separated string and update/add the parameter
|
||||
searchParams.set(`openFaqItems-${slug}`, openFaqItems.map(String).join(','));
|
||||
|
||||
// Construct the new URL, preserve existing parameters
|
||||
const newUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}?${searchParams.toString()}`;
|
||||
|
||||
// Use history.pushState to change the URL without reloading the page
|
||||
window.history.pushState({ path: newUrl }, '', newUrl);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
// biome-ignore lint: we need dangerouslySetInnerHTML here, and since we're the ones setting the content it's should be safe
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqStructuredData) }}
|
||||
/>
|
||||
<Accordion
|
||||
allowMultipleExpanded={true}
|
||||
allowZeroExpanded={true}
|
||||
onChange={handleChange}
|
||||
preExpanded={preExpanded}
|
||||
>
|
||||
{rows.map((row, index) => (
|
||||
<AccordionItem key={index}>
|
||||
<AccordionItemHeading aria-level="2">
|
||||
<AccordionItemButton>{row.title}</AccordionItemButton>
|
||||
</AccordionItemHeading>
|
||||
<AccordionItemPanel>
|
||||
<ReactMarkdown>{row.content}</ReactMarkdown>
|
||||
</AccordionItemPanel>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</>
|
||||
);
|
||||
};
|
Loading…
Reference in a new issue