mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-05 13:20:31 +03:00
Rebuild object docs
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import React, { useState } from "react";
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
import ConfigTabs from "@site/src/components/ConfigTabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
import { marked } from "marked";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
marked.setOptions({ gfm: true });
|
||||
|
||||
/**
|
||||
* @typedef {Object} Model
|
||||
* @property {string} key
|
||||
* @property {string} label
|
||||
* @property {boolean} recommended
|
||||
* @property {string} download Markdown for the "download the model" step.
|
||||
* @property {string} ui Markdown for the Frigate UI configuration step.
|
||||
* @property {string} yaml Raw YAML for the configuration step.
|
||||
*/
|
||||
|
||||
function Markdown({ children }) {
|
||||
return (
|
||||
<div
|
||||
className={styles.markdown}
|
||||
dangerouslySetInnerHTML={{ __html: marked.parse(children || "") }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ models: Model[] }} props
|
||||
*/
|
||||
export default function ModelConfigDropdown({ models }) {
|
||||
const [selectedModelIndex, setSelectedModelIndex] = useState(0);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const selectedModel = models[selectedModelIndex];
|
||||
const hasChoices = models.length > 1;
|
||||
|
||||
const handleModelSelect = (index) => {
|
||||
setSelectedModelIndex(index);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div
|
||||
className={`${styles.dropdown} ${isOpen ? styles.open : ""} ${
|
||||
hasChoices ? "" : styles.static
|
||||
}`}
|
||||
onClick={hasChoices ? () => setIsOpen(!isOpen) : undefined}
|
||||
>
|
||||
<div className={styles.dropdownContent}>
|
||||
<span className={styles.modelName}>
|
||||
{selectedModel.recommended && (
|
||||
<span className={styles.recommendedBadge}>Recommended</span>
|
||||
)}
|
||||
{selectedModel.label}
|
||||
</span>
|
||||
{hasChoices && (
|
||||
<span className={styles.arrow}>{isOpen ? "▲" : "▼"}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isOpen && hasChoices && (
|
||||
<div className={styles.menu}>
|
||||
{models.map((model, index) => (
|
||||
<div
|
||||
key={model.key}
|
||||
className={`${styles.menuItem} ${
|
||||
index === selectedModelIndex ? styles.menuItemActive : ""
|
||||
}`}
|
||||
onClick={() => handleModelSelect(index)}
|
||||
>
|
||||
{model.recommended && (
|
||||
<span className={styles.recommendedBadge}>Recommended</span>
|
||||
)}
|
||||
{model.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.panel}>
|
||||
<div className={styles.step}>
|
||||
<h4 className={styles.stepTitle}>Step 1 — Download the model</h4>
|
||||
<Markdown>{selectedModel.download}</Markdown>
|
||||
</div>
|
||||
|
||||
<div className={styles.step}>
|
||||
<h4 className={styles.stepTitle}>Step 2 — Configure the detector</h4>
|
||||
<ConfigTabs>
|
||||
<TabItem value="ui">
|
||||
<Markdown>{selectedModel.ui}</Markdown>
|
||||
</TabItem>
|
||||
<TabItem value="yaml">
|
||||
<CodeBlock language="yaml">{selectedModel.yaml}</CodeBlock>
|
||||
</TabItem>
|
||||
</ConfigTabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/* ===================================================================
|
||||
ModelConfigDropdown — styles
|
||||
=================================================================== */
|
||||
|
||||
.wrapper {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
/* --- Dropdown button --- */
|
||||
|
||||
.dropdown {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
border: 1px solid var(--ifm-color-emphasis-400);
|
||||
border-radius: 8px;
|
||||
background: var(--ifm-background-color);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
}
|
||||
|
||||
[data-theme="light"] .dropdown {
|
||||
border: 1px solid #d0d7de;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown {
|
||||
border: 1px solid var(--ifm-color-emphasis-300);
|
||||
background: #21262d;
|
||||
}
|
||||
|
||||
.dropdown:hover {
|
||||
border-color: var(--ifm-color-primary);
|
||||
box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown:hover {
|
||||
box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest);
|
||||
}
|
||||
|
||||
.dropdown.open {
|
||||
border-color: var(--ifm-color-primary);
|
||||
box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown.open {
|
||||
border-color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
/* Single-model detectors render the label without a clickable menu. */
|
||||
.dropdown.static {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dropdown.static:hover {
|
||||
border-color: var(--ifm-color-emphasis-400);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="light"] .dropdown.static:hover {
|
||||
border-color: #d0d7de;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .dropdown.static:hover {
|
||||
border-color: var(--ifm-color-emphasis-300);
|
||||
}
|
||||
|
||||
.dropdownContent {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
/* --- Model menu --- */
|
||||
|
||||
.menu {
|
||||
margin-top: 0.25rem;
|
||||
border: 1px solid var(--ifm-color-emphasis-400);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--ifm-background-color);
|
||||
}
|
||||
|
||||
[data-theme="light"] .menu {
|
||||
border: 1px solid #d0d7de;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .menu {
|
||||
border: 1px solid var(--ifm-color-emphasis-300);
|
||||
background: #21262d;
|
||||
}
|
||||
|
||||
.menuItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.6rem 1rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
color: var(--ifm-font-color-base);
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.menuItem:not(:last-child) {
|
||||
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
||||
}
|
||||
|
||||
.menuItem:hover {
|
||||
background: var(--ifm-color-emphasis-100);
|
||||
}
|
||||
|
||||
.menuItemActive {
|
||||
font-weight: var(--ifm-font-weight-semibold);
|
||||
background: var(--ifm-color-primary-lightest);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .menuItem:hover {
|
||||
background: #2b3139;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .menuItemActive {
|
||||
background: #2b3139;
|
||||
}
|
||||
|
||||
.modelName {
|
||||
font-weight: var(--ifm-font-weight-semibold);
|
||||
color: var(--ifm-font-color-base);
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.recommendedBadge {
|
||||
display: inline-block;
|
||||
background: var(--ifm-color-success);
|
||||
color: #fff;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 0.7rem;
|
||||
color: var(--ifm-font-color-secondary);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.dropdown.open .arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* --- Panel --- */
|
||||
|
||||
.panel {
|
||||
margin-top: 0.5rem;
|
||||
border: 1px solid var(--ifm-color-emphasis-400);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--ifm-background-color);
|
||||
}
|
||||
|
||||
[data-theme="light"] .panel {
|
||||
border: 1px solid #d0d7de;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .panel {
|
||||
border: 1px solid var(--ifm-color-emphasis-300);
|
||||
background: #21262d;
|
||||
}
|
||||
|
||||
/* --- Steps --- */
|
||||
|
||||
.step {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.step:not(:last-child) {
|
||||
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
||||
}
|
||||
|
||||
.stepTitle {
|
||||
margin: 0 0 0.75rem 0;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
/* Rendered markdown (download + Frigate UI instructions). */
|
||||
|
||||
.markdown {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.markdown > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown a {
|
||||
color: var(--ifm-color-primary);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
.markdown table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin: 0.75rem 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.markdown pre {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
Reference in New Issue
Block a user