add grey out feature, update tag and hero text (#386)
* update tag and hover page * remove tags * add filter tag * add clear all * changes for checkbox as array * update Azure AI Search * fix bug --------- Co-authored-by: Victor Vazquez <vhvb1989@gmail.com>
This commit is contained in:
Родитель
7bb7b89cef
Коммит
9df16bb6ef
|
@ -17,13 +17,28 @@ import { Tags, type TagType } from "../../../data/tags";
|
|||
import { TagList } from "../../../data/users";
|
||||
import styles from "./styles.module.css";
|
||||
import { useColorMode } from "@docusaurus/theme-common";
|
||||
import { useHistory } from "@docusaurus/router";
|
||||
import { prepareUserState } from "@site/src/pages/index";
|
||||
import { UserState } from "../ShowcaseTemplateSearch";
|
||||
|
||||
function ShowcaseFilterViewAll({
|
||||
tags,
|
||||
number,
|
||||
activeTags,
|
||||
selectedCheckbox,
|
||||
setSelectedCheckbox,
|
||||
location,
|
||||
readSearchTags,
|
||||
replaceSearchTags,
|
||||
}: {
|
||||
tags: TagType[];
|
||||
number: string;
|
||||
activeTags: TagType[];
|
||||
selectedCheckbox: TagType[];
|
||||
setSelectedCheckbox: React.Dispatch<React.SetStateAction<TagType[]>>;
|
||||
location;
|
||||
readSearchTags: (search: string) => TagType[];
|
||||
replaceSearchTags: (search: string, newTags: TagType[]) => string;
|
||||
}) {
|
||||
const [openItems, setOpenItems] = React.useState(["0"]);
|
||||
const handleToggle: AccordionToggleEventHandler<string> = (event, data) => {
|
||||
|
@ -62,11 +77,31 @@ function ShowcaseFilterViewAll({
|
|||
className={styles.checkboxListItem}
|
||||
style={{ marginBottom: "7px" }}
|
||||
>
|
||||
<ShowcaseTagSelect id={id} tag={tag} label={tagObject.label} />
|
||||
<ShowcaseTagSelect
|
||||
id={id}
|
||||
tag={tag}
|
||||
label={tagObject.label}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div key={key} className={styles.checkboxListItem}>
|
||||
<ShowcaseTagSelect id={id} tag={tag} label={tagObject.label} />
|
||||
<ShowcaseTagSelect
|
||||
id={id}
|
||||
tag={tag}
|
||||
label={tagObject.label}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
@ -90,6 +125,12 @@ function ShowcaseFilterViewAll({
|
|||
id={id}
|
||||
tag={tag}
|
||||
label={tagObject.label}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -118,7 +159,25 @@ function ShowcaseFilterViewAll({
|
|||
);
|
||||
}
|
||||
|
||||
export default function ShowcaseLeftFilters() {
|
||||
export default function ShowcaseLeftFilters({
|
||||
activeTags,
|
||||
selectedCheckbox,
|
||||
setSelectedCheckbox,
|
||||
location,
|
||||
selectedTags,
|
||||
setSelectedTags,
|
||||
readSearchTags,
|
||||
replaceSearchTags,
|
||||
}: {
|
||||
activeTags: TagType[];
|
||||
selectedCheckbox: TagType[];
|
||||
setSelectedCheckbox: React.Dispatch<React.SetStateAction<TagType[]>>;
|
||||
location;
|
||||
selectedTags: TagType[];
|
||||
setSelectedTags: React.Dispatch<React.SetStateAction<TagType[]>>;
|
||||
readSearchTags: (search: string) => TagType[];
|
||||
replaceSearchTags: (search: string, newTags: TagType[]) => string;
|
||||
}) {
|
||||
const sortTagList = TagList.sort();
|
||||
const uncategoryTag = TagList.filter((tag) => {
|
||||
const tagObject = Tags[tag];
|
||||
|
@ -152,18 +211,22 @@ export default function ShowcaseLeftFilters() {
|
|||
const tagObject = Tags[tag];
|
||||
return tagObject.type === "Topic";
|
||||
});
|
||||
const [openItems, setOpenItems] = React.useState([
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
]);
|
||||
const [openItems, setOpenItems] = React.useState([]);
|
||||
const handleToggle: AccordionToggleEventHandler<string> = (event, data) => {
|
||||
setOpenItems(data.openItems);
|
||||
};
|
||||
const history = useHistory();
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const clearAll = () => {
|
||||
setSelectedCheckbox([]);
|
||||
setSelectedTags([]);
|
||||
searchParams.delete("tags");
|
||||
history.push({
|
||||
...location,
|
||||
search: searchParams.toString(),
|
||||
state: prepareUserState(),
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Accordion
|
||||
openItems={openItems}
|
||||
|
@ -172,14 +235,13 @@ export default function ShowcaseLeftFilters() {
|
|||
collapsible
|
||||
>
|
||||
<div style={{ paddingBottom: "7px" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "20px",
|
||||
fontWeight: "500",
|
||||
padding: "0 0 15px 12px",
|
||||
}}
|
||||
>
|
||||
Filter by
|
||||
<div className={styles.filterTop}>
|
||||
<div className={styles.filterBy}>Filter by</div>
|
||||
{selectedTags.length > 0 ? (
|
||||
<div className={styles.clearAll} onClick={clearAll}>
|
||||
Clear all
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{uncategoryTag.map((tag) => {
|
||||
const tagObject = Tags[tag];
|
||||
|
@ -192,7 +254,17 @@ export default function ShowcaseLeftFilters() {
|
|||
className={styles.checkboxListItem}
|
||||
style={{ paddingLeft: "12px" }}
|
||||
>
|
||||
<ShowcaseTagSelect id={id} tag={tag} label={tagObject.label} />
|
||||
<ShowcaseTagSelect
|
||||
id={id}
|
||||
tag={tag}
|
||||
label={tagObject.label}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
@ -208,7 +280,16 @@ export default function ShowcaseLeftFilters() {
|
|||
<div style={{ fontSize: "16px", fontWeight: "500" }}>Language</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={languageTag} number={"1"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={languageTag}
|
||||
number={"1"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
|
@ -223,7 +304,16 @@ export default function ShowcaseLeftFilters() {
|
|||
<div style={{ fontSize: "16px", fontWeight: "500" }}>Framework</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={frameworkTag} number={"2"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={frameworkTag}
|
||||
number={"2"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
|
@ -238,7 +328,16 @@ export default function ShowcaseLeftFilters() {
|
|||
<div style={{ fontSize: "16px", fontWeight: "500" }}>Services</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={servicesTag} number={"3"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={servicesTag}
|
||||
number={"3"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
|
@ -253,7 +352,16 @@ export default function ShowcaseLeftFilters() {
|
|||
<div style={{ fontSize: "16px", fontWeight: "500" }}>Database</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={databaseTag} number={"4"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={databaseTag}
|
||||
number={"4"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
|
@ -270,7 +378,16 @@ export default function ShowcaseLeftFilters() {
|
|||
</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={infrastructureAsCodeTag} number={"5"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={infrastructureAsCodeTag}
|
||||
number={"5"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
|
@ -285,7 +402,16 @@ export default function ShowcaseLeftFilters() {
|
|||
<div style={{ fontSize: "16px", fontWeight: "500" }}>Tools</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={otherTag} number={"6"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={otherTag}
|
||||
number={"6"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
|
@ -300,7 +426,16 @@ export default function ShowcaseLeftFilters() {
|
|||
<div style={{ fontSize: "16px", fontWeight: "500" }}>Topic</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<ShowcaseFilterViewAll tags={topicTag} number={"7"} />
|
||||
<ShowcaseFilterViewAll
|
||||
tags={topicTag}
|
||||
number={"7"}
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
|
|
@ -15,3 +15,25 @@
|
|||
.color {
|
||||
color: var(--ifm-color-purple);
|
||||
}
|
||||
|
||||
.filterTop {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 0 15px 12px;
|
||||
}
|
||||
|
||||
.clearAll {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
text-decoration-line: underline;
|
||||
cursor: pointer;
|
||||
color: var(--ifm-color-purple);
|
||||
}
|
||||
|
||||
.filterBy {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
|
|
@ -3,47 +3,37 @@
|
|||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useState, useEffect } from "react";
|
||||
import { useHistory, useLocation } from "@docusaurus/router";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { useHistory } from "@docusaurus/router";
|
||||
import { toggleListItem } from "@site/src/utils/jsUtils";
|
||||
import { prepareUserState } from "@site/src/pages/index";
|
||||
import { type TagType } from "@site/src/data/tags";
|
||||
|
||||
import { Checkbox } from "@fluentui/react-components";
|
||||
|
||||
const TagQueryStringKey = "tags";
|
||||
|
||||
export function readSearchTags(search: string): TagType[] {
|
||||
return new URLSearchParams(search).getAll(TagQueryStringKey) as TagType[];
|
||||
}
|
||||
|
||||
function replaceSearchTags(search: string, newTags: TagType[]) {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
searchParams.delete(TagQueryStringKey);
|
||||
newTags.forEach((tag) => searchParams.append(TagQueryStringKey, tag));
|
||||
return searchParams.toString();
|
||||
}
|
||||
|
||||
export default function ShowcaseTagSelect(
|
||||
// id: string,
|
||||
{
|
||||
export default function ShowcaseTagSelect({
|
||||
label,
|
||||
tag,
|
||||
id,
|
||||
activeTags,
|
||||
selectedCheckbox,
|
||||
setSelectedCheckbox,
|
||||
location,
|
||||
readSearchTags,
|
||||
replaceSearchTags,
|
||||
}: {
|
||||
label: string;
|
||||
tag: TagType;
|
||||
id: string;
|
||||
}
|
||||
): JSX.Element {
|
||||
const location = useLocation();
|
||||
activeTags: TagType[];
|
||||
selectedCheckbox: TagType[];
|
||||
setSelectedCheckbox: React.Dispatch<React.SetStateAction<TagType[]>>;
|
||||
location;
|
||||
readSearchTags: (search: string) => TagType[];
|
||||
replaceSearchTags: (search: string, newTags: TagType[]) => string;
|
||||
}): JSX.Element {
|
||||
const history = useHistory();
|
||||
const [selected, setSelected] = useState(false);
|
||||
useEffect(() => {
|
||||
const tags = readSearchTags(location.search);
|
||||
setSelected(tags.includes(tag));
|
||||
}, [tag, location]);
|
||||
const toggleTag = useCallback(() => {
|
||||
// updates only the url query
|
||||
const toggleTag = () => {
|
||||
const tags = readSearchTags(location.search);
|
||||
const newTags = toggleListItem(tags, tag);
|
||||
const newSearch = replaceSearchTags(location.search, newTags);
|
||||
|
@ -52,9 +42,19 @@ export default function ShowcaseTagSelect(
|
|||
search: newSearch,
|
||||
state: prepareUserState(),
|
||||
});
|
||||
}, [tag, location, history]);
|
||||
const template = id.replace("showcase_checkbox_id_", "")
|
||||
const contentForAdobeAnalytics = `{\"id\":\"${template}\",\"cN\":\"Tags\"}`
|
||||
};
|
||||
|
||||
const template = id.replace("showcase_checkbox_id_", "");
|
||||
const contentForAdobeAnalytics = `{\"id\":\"${template}\",\"cN\":\"Tags\"}`;
|
||||
|
||||
const toggleCheck = (tag: TagType) => {
|
||||
if (selectedCheckbox.includes(tag)) {
|
||||
setSelectedCheckbox(selectedCheckbox.filter((item) => item !== tag));
|
||||
} else {
|
||||
setSelectedCheckbox([...selectedCheckbox, tag]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
|
@ -64,10 +64,15 @@ export default function ShowcaseTagSelect(
|
|||
if (e.key === "Enter") {
|
||||
toggleTag();
|
||||
}
|
||||
toggleCheck(tag);
|
||||
}}
|
||||
onChange={toggleTag}
|
||||
checked={selected}
|
||||
onChange={() => {
|
||||
toggleTag();
|
||||
toggleCheck(tag);
|
||||
}}
|
||||
checked={selectedCheckbox.includes(tag)}
|
||||
label={label}
|
||||
disabled={!activeTags?.includes(tag)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ import { useColorMode } from "@docusaurus/theme-common";
|
|||
|
||||
const TITLE = "Template Library";
|
||||
const DESCRIPTION =
|
||||
"A community-contributed template gallery built to work with the Azure Developer CLI.";
|
||||
"An open-source template gallery to get started with Azure.";
|
||||
const ADD_URL = "https://aka.ms/azd";
|
||||
export var InputValue: string | null = null;
|
||||
|
||||
|
@ -159,17 +159,28 @@ export default function ShowcaseTemplateSearch() {
|
|||
size={300}
|
||||
style={{
|
||||
color: "#242424",
|
||||
padding: "20px 0",
|
||||
paddingTop: "20px",
|
||||
}}
|
||||
>
|
||||
Not familiar with the Azure Developer CLI (azd)?
|
||||
Each template is a fully working, cloud-ready application deployable
|
||||
with the Azure Developer CLI (azd).{" "}
|
||||
</Text>
|
||||
<Text
|
||||
align="center"
|
||||
size={300}
|
||||
style={{
|
||||
color: "#242424",
|
||||
paddingBottom: "20px",
|
||||
}}
|
||||
>
|
||||
New to azd? Welcome!
|
||||
<FluentUILink
|
||||
href={ADD_URL}
|
||||
target="_blank"
|
||||
style={{ paddingLeft: "3px" }}
|
||||
className={styles.learnMoreColor}
|
||||
>
|
||||
Learn more
|
||||
Learn more in our docs.
|
||||
</FluentUILink>
|
||||
</Text>
|
||||
</div>
|
||||
|
|
|
@ -47,7 +47,6 @@ export type TagType =
|
|||
| "keyvault"
|
||||
| "aca"
|
||||
| "mongodb"
|
||||
| "signalR"
|
||||
| "functions"
|
||||
| "blobstorage"
|
||||
| "azuredb-postgreSQL"
|
||||
|
@ -59,11 +58,9 @@ export type TagType =
|
|||
| "servicebus"
|
||||
| "vnets"
|
||||
| "fastapi"
|
||||
| "fhir"
|
||||
| "ahds"
|
||||
| "appinsights"
|
||||
| "loganalytics"
|
||||
| "cognitivesearch"
|
||||
| "aisearch"
|
||||
| "openai"
|
||||
| "azureai"
|
||||
| "flask"
|
||||
|
@ -75,7 +72,6 @@ export type TagType =
|
|||
| "sapcloudsdk"
|
||||
| "nestjs"
|
||||
| "dataverse"
|
||||
| "chatgpt"
|
||||
| "aks"
|
||||
| "azurecdn"
|
||||
| "frontdoor"
|
||||
|
@ -212,11 +208,6 @@ export const Tags: { [type in TagType]: Tag } = {
|
|||
description: "Template architecture uses Thymeleaf template engine",
|
||||
type: "Tools",
|
||||
},
|
||||
chatgpt: {
|
||||
label: "ChatGPT",
|
||||
description: "Template architecture uses ChatGPT application",
|
||||
type: "Tools",
|
||||
},
|
||||
"dall-e": {
|
||||
label: "Dall-E",
|
||||
description: "Template architecture uses Dall-E",
|
||||
|
@ -345,12 +336,6 @@ export const Tags: { [type in TagType]: Tag } = {
|
|||
},
|
||||
|
||||
// ---- Service
|
||||
fhir: {
|
||||
label: "FHIR Service",
|
||||
description:
|
||||
"Template architecture uses Fast Healthcare Interoperability Resources (FHIR) service",
|
||||
type: "Service",
|
||||
},
|
||||
dataverse: {
|
||||
label: "Dataverse",
|
||||
description: "Template architecture uses Microsoft Dataverse",
|
||||
|
@ -368,14 +353,6 @@ export const Tags: { [type in TagType]: Tag } = {
|
|||
},
|
||||
|
||||
// ---- Azure Services
|
||||
ahds: {
|
||||
label: "Azure Health Data Service",
|
||||
description:
|
||||
"Template architecture uses Azure Health Data Services workspace",
|
||||
azureIcon: "./img/Azure-Health-Data-Service.svg",
|
||||
url: "https://azure.microsoft.com/products/health-data-services/",
|
||||
type: "Service",
|
||||
},
|
||||
appinsights: {
|
||||
label: "Azure Application Insights",
|
||||
description: "Template architecture uses Azure Application Insights",
|
||||
|
@ -425,13 +402,6 @@ export const Tags: { [type in TagType]: Tag } = {
|
|||
url: "https://azure.microsoft.com/products/cosmos-db/",
|
||||
type: "Service",
|
||||
},
|
||||
signalR: {
|
||||
label: "Azure SignalR",
|
||||
description: "Template architecture uses Azure SignalR",
|
||||
azureIcon: "./img/Azure-SignalR.svg",
|
||||
url: "https://azure.microsoft.com/products/signalr-service",
|
||||
type: "Service",
|
||||
},
|
||||
functions: {
|
||||
label: "Azure Functions",
|
||||
description: "Template architecture uses Azure Functions",
|
||||
|
@ -488,11 +458,11 @@ export const Tags: { [type in TagType]: Tag } = {
|
|||
url: "https://azure.microsoft.com/products/virtual-network",
|
||||
type: "Service",
|
||||
},
|
||||
cognitivesearch: {
|
||||
label: "Azure Cognitive Search",
|
||||
description: "Template architecture uses Azure Cognitive Search",
|
||||
azureIcon: "./img/Azure-Cognitive-Search.svg",
|
||||
url: "https://azure.microsoft.com/products/ai-services/cognitive-search",
|
||||
aisearch: {
|
||||
label: "Azure AI Search",
|
||||
description: "Template architecture uses Azure AI Search",
|
||||
azureIcon: "./img/Azure-AI-Search.svg",
|
||||
url: "https://azure.microsoft.com/products/ai-services/ai-search",
|
||||
type: "Service",
|
||||
},
|
||||
openai: {
|
||||
|
|
|
@ -3,17 +3,55 @@
|
|||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import React, { useState, useMemo, useEffect } from "react";
|
||||
import { readSearchTags } from "../components/gallery/ShowcaseTagSelect";
|
||||
import { useLocation } from "@docusaurus/router";
|
||||
import React, { useState, useMemo, useEffect, useCallback } from "react";
|
||||
import {
|
||||
UserState,
|
||||
InputValue,
|
||||
} from "../components/gallery/ShowcaseTemplateSearch";
|
||||
import { type User, type TagType } from "../data/tags";
|
||||
import { Tags, type User, type TagType } from "../data/tags";
|
||||
import { sortedUsers, unsortedUsers } from "../data/users";
|
||||
import { Text, Combobox, Option, Spinner } from "@fluentui/react-components";
|
||||
import {
|
||||
Text,
|
||||
Combobox,
|
||||
Option,
|
||||
Spinner,
|
||||
Badge,
|
||||
} from "@fluentui/react-components";
|
||||
import ShowcaseCards from "./ShowcaseCards";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import styles from "./styles.module.css";
|
||||
import { useColorMode } from "@docusaurus/theme-common";
|
||||
import { useHistory } from "@docusaurus/router";
|
||||
import { toggleListItem } from "@site/src/utils/jsUtils";
|
||||
import { prepareUserState } from "./index";
|
||||
|
||||
const TagQueryStringKey2 = "tags";
|
||||
|
||||
const readSearchTags2 = (search: string): TagType[] => {
|
||||
return new URLSearchParams(search).getAll(TagQueryStringKey2) as TagType[];
|
||||
}
|
||||
|
||||
function replaceSearchTags(search: string, newTags: TagType[]) {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
searchParams.delete(TagQueryStringKey2);
|
||||
newTags.forEach((tag) => searchParams.append(TagQueryStringKey2, tag));
|
||||
return searchParams.toString();
|
||||
}
|
||||
|
||||
// updates only the url query
|
||||
const toggleTag = (tag: TagType, location: Location) => {
|
||||
const history = useHistory();
|
||||
return useCallback(() => {
|
||||
const tags = readSearchTags2(location.search);
|
||||
const newTags = toggleListItem(tags, tag);
|
||||
const newSearch = replaceSearchTags(location.search, newTags);
|
||||
history.push({
|
||||
...location,
|
||||
search: newSearch,
|
||||
state: prepareUserState(),
|
||||
});
|
||||
}, [tag, location, history]);
|
||||
}
|
||||
|
||||
function restoreUserState(userState: UserState | null) {
|
||||
const { scrollTopPosition, focusedElementId } = userState ?? {
|
||||
|
@ -64,7 +102,7 @@ function filterUsers(
|
|||
user.title.toLowerCase().includes(searchName.toLowerCase())
|
||||
);
|
||||
}
|
||||
if (!selectedTags && selectedTags.length === 0) {
|
||||
if (!selectedTags || selectedTags.length === 0) {
|
||||
return users;
|
||||
}
|
||||
return users.filter((user) => {
|
||||
|
@ -75,21 +113,103 @@ function filterUsers(
|
|||
});
|
||||
}
|
||||
|
||||
export default function ShowcaseCardPage() {
|
||||
function FilterAppliedBar({
|
||||
clearAll,
|
||||
selectedTags,
|
||||
}: {
|
||||
clearAll;
|
||||
selectedTags: TagType[];
|
||||
}) {
|
||||
const { colorMode } = useColorMode();
|
||||
return selectedTags.length > 0 ? (
|
||||
<div
|
||||
style={{
|
||||
paddingTop: "32px",
|
||||
display: "flex",
|
||||
gap: "12px",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontWeight: "400",
|
||||
lineHeight: "20px",
|
||||
}}
|
||||
>
|
||||
Filters applied:
|
||||
</div>
|
||||
{selectedTags.map((tag, index) => {
|
||||
const tagObject = Tags[tag];
|
||||
const key = `showcase_checkbox_key_${tag}`;
|
||||
const id = `showcase_checkbox_id_${tag}`;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
appearance="tint"
|
||||
size="extra-large"
|
||||
color="brand"
|
||||
shape="rounded"
|
||||
icon={
|
||||
colorMode != "dark" ? (
|
||||
<img
|
||||
src={useBaseUrl("/img/lightModePurpleClose.svg")}
|
||||
height={20}
|
||||
alt="Close"
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={useBaseUrl("/img/darkModePurpleClose.svg")}
|
||||
height={20}
|
||||
alt="Close"
|
||||
/>
|
||||
)
|
||||
}
|
||||
iconPosition="after"
|
||||
className={styles.filterBadge}
|
||||
onClick={() => {
|
||||
toggleTag(tag, location);
|
||||
}}
|
||||
>
|
||||
{tagObject.label}
|
||||
</Badge>
|
||||
);
|
||||
})}
|
||||
<div className={styles.clearAll} onClick={clearAll}>
|
||||
Clear all
|
||||
</div>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
export default function ShowcaseCardPage({
|
||||
setActiveTags,
|
||||
selectedTags,
|
||||
location,
|
||||
setSelectedTags,
|
||||
readSearchTags,
|
||||
replaceSearchTags,
|
||||
}: {
|
||||
setActiveTags: React.Dispatch<React.SetStateAction<TagType[]>>;
|
||||
selectedTags: TagType[];
|
||||
location;
|
||||
setSelectedTags: React.Dispatch<React.SetStateAction<TagType[]>>;
|
||||
readSearchTags: (search: string) => TagType[];
|
||||
replaceSearchTags: (search: string, newTags: TagType[]) => string;
|
||||
}) {
|
||||
const [selectedOptions, setSelectedOptions] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [selectedTags, setSelectedTags] = useState<TagType[]>([]);
|
||||
const [searchName, setSearchName] = useState<string | null>(null);
|
||||
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
|
||||
const location = useLocation<UserState>();
|
||||
const clearAll = () => {
|
||||
setSelectedTags([]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTags(readSearchTags(location.search));
|
||||
setSelectedUsers(readSortChoice(selectedOptions[0]));
|
||||
setSearchName(readSearchName(location.search));
|
||||
restoreUserState(location.state);
|
||||
|
||||
setLoading(false);
|
||||
}, [location, selectedOptions]);
|
||||
|
||||
|
@ -98,6 +218,12 @@ export default function ShowcaseCardPage() {
|
|||
[selectedUsers, selectedTags, searchName]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const unionTags = new Set<TagType>();
|
||||
cards.forEach((user) => user.tags.forEach((tag) => unionTags.add(tag)));
|
||||
setActiveTags(Array.from(unionTags));
|
||||
}, [cards]);
|
||||
|
||||
const sortByOnSelect = (event, data) => {
|
||||
setLoading(true);
|
||||
setSelectedOptions(data.selectedOptions);
|
||||
|
@ -158,6 +284,7 @@ export default function ShowcaseCardPage() {
|
|||
</Combobox>
|
||||
</div>
|
||||
</div>
|
||||
{/* <FilterAppliedBar clearAll={clearAll} selectedTags={selectedTags} /> */}
|
||||
{loading ? (
|
||||
<Spinner labelPosition="below" label="Loading..." />
|
||||
) : (
|
||||
|
|
|
@ -16,10 +16,12 @@ import {
|
|||
} from "@fluentui/react-components";
|
||||
import { initializeIcons } from "@fluentui/react/lib/Icons";
|
||||
import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
|
||||
|
||||
import { type TagType } from "@site/src/data/tags";
|
||||
import { TagList } from "@site/src/data/users";
|
||||
import styles from "./styles.module.css";
|
||||
import { useColorMode } from "@docusaurus/theme-common";
|
||||
import ShowcaseCardPage from "./ShowcaseCardPage";
|
||||
import { useLocation } from "@docusaurus/router";
|
||||
|
||||
initializeIcons();
|
||||
|
||||
|
@ -34,15 +36,32 @@ export function prepareUserState(): UserState | undefined {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const TagQueryStringKey = "tags";
|
||||
const readSearchTags = (search: string): TagType[] => {
|
||||
return new URLSearchParams(search).getAll(TagQueryStringKey) as TagType[];
|
||||
};
|
||||
const replaceSearchTags = (search: string, newTags: TagType[]) => {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
searchParams.delete(TagQueryStringKey);
|
||||
newTags.forEach((tag) => searchParams.append(TagQueryStringKey, tag));
|
||||
return searchParams.toString();
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const { colorMode } = useColorMode();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [activeTags, setActiveTags] = useState<TagType[]>(TagList);
|
||||
const [selectedCheckbox, setSelectedCheckbox] = useState<TagType[]>([]);
|
||||
const location = useLocation<UserState>();
|
||||
const [selectedTags, setSelectedTags] = useState<TagType[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTags(readSearchTags(location.search));
|
||||
setSelectedCheckbox(readSearchTags(location.search));
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
}, []);
|
||||
}, [location]);
|
||||
|
||||
return !loading ? (
|
||||
<FluentProvider
|
||||
|
@ -51,10 +70,26 @@ const App = () => {
|
|||
<ShowcaseTemplateSearch />
|
||||
<div className={styles.filterAndCard}>
|
||||
<div className={styles.filter}>
|
||||
<ShowcaseLeftFilters />
|
||||
<ShowcaseLeftFilters
|
||||
activeTags={activeTags}
|
||||
selectedCheckbox={selectedCheckbox}
|
||||
setSelectedCheckbox={setSelectedCheckbox}
|
||||
location={location}
|
||||
setSelectedTags={setSelectedTags}
|
||||
selectedTags={selectedTags}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.card}>
|
||||
<ShowcaseCardPage />
|
||||
<ShowcaseCardPage
|
||||
setActiveTags={setActiveTags}
|
||||
selectedTags={selectedTags}
|
||||
location={location}
|
||||
setSelectedTags={setSelectedTags}
|
||||
readSearchTags={readSearchTags}
|
||||
replaceSearchTags={replaceSearchTags}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</FluentProvider>
|
||||
|
|
|
@ -124,6 +124,27 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.clearAll {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
text-decoration-line: underline;
|
||||
cursor: pointer;
|
||||
color: var(--ifm-color-purple);
|
||||
}
|
||||
|
||||
.filterBadge {
|
||||
color: var(--ifm-color-purple);
|
||||
cursor: pointer;
|
||||
border: 1px solid #d2ccf8;
|
||||
background: #f9f8fe;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .filterBadge {
|
||||
border: 1px solid #221d46;
|
||||
background: #3f3682;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.filterAndCard {
|
||||
flex-direction: column;
|
||||
|
|
До Ширина: | Высота: | Размер: 1.2 KiB После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -0,0 +1,5 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Dismiss">
|
||||
<path id="Shape" d="M4.08859 4.21569L4.14645 4.14645C4.32001 3.97288 4.58944 3.9536 4.78431 4.08859L4.85355 4.14645L10 9.293L15.1464 4.14645C15.32 3.97288 15.5894 3.9536 15.7843 4.08859L15.8536 4.14645C16.0271 4.32001 16.0464 4.58944 15.9114 4.78431L15.8536 4.85355L10.707 10L15.8536 15.1464C16.0271 15.32 16.0464 15.5894 15.9114 15.7843L15.8536 15.8536C15.68 16.0271 15.4106 16.0464 15.2157 15.9114L15.1464 15.8536L10 10.707L4.85355 15.8536C4.67999 16.0271 4.41056 16.0464 4.21569 15.9114L4.14645 15.8536C3.97288 15.68 3.9536 15.4106 4.08859 15.2157L4.14645 15.1464L9.293 10L4.14645 4.85355C3.97288 4.67999 3.9536 4.41056 4.08859 4.21569L4.14645 4.14645L4.08859 4.21569Z" fill="#A79CF1"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 815 B |
|
@ -0,0 +1,5 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Dismiss">
|
||||
<path id="Shape" d="M4.08859 4.21569L4.14645 4.14645C4.32001 3.97288 4.58944 3.9536 4.78431 4.08859L4.85355 4.14645L10 9.293L15.1464 4.14645C15.32 3.97288 15.5894 3.9536 15.7843 4.08859L15.8536 4.14645C16.0271 4.32001 16.0464 4.58944 15.9114 4.78431L15.8536 4.85355L10.707 10L15.8536 15.1464C16.0271 15.32 16.0464 15.5894 15.9114 15.7843L15.8536 15.8536C15.68 16.0271 15.4106 16.0464 15.2157 15.9114L15.1464 15.8536L10 10.707L4.85355 15.8536C4.67999 16.0271 4.41056 16.0464 4.21569 15.9114L4.14645 15.8536C3.97288 15.68 3.9536 15.4106 4.08859 15.2157L4.14645 15.1464L9.293 10L4.14645 4.85355C3.97288 4.67999 3.9536 4.41056 4.08859 4.21569L4.14645 4.14645L4.08859 4.21569Z" fill="#6656D1"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 815 B |
|
@ -414,9 +414,9 @@
|
|||
"aks",
|
||||
"kubernetes",
|
||||
"aca",
|
||||
"cognitivesearch",
|
||||
"aisearch",
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"rediscache",
|
||||
"ai",
|
||||
"msft"
|
||||
|
@ -433,7 +433,7 @@
|
|||
"bicep",
|
||||
"python",
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"ai",
|
||||
"flask",
|
||||
"aca",
|
||||
|
@ -451,7 +451,7 @@
|
|||
"bicep",
|
||||
"java",
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"ai",
|
||||
"blobstorage",
|
||||
"azurespringapps",
|
||||
|
@ -630,8 +630,8 @@
|
|||
"source": "https://github.com/Azure-Samples/azure-search-openai-demo",
|
||||
"tags": [
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"cognitivesearch",
|
||||
"gpt",
|
||||
"aisearch",
|
||||
"python",
|
||||
"typescript",
|
||||
"bicep",
|
||||
|
@ -745,7 +745,7 @@
|
|||
"source": "https://github.com/Azure-Samples/function-csharp-ai-textsummarize",
|
||||
"tags": [
|
||||
"functions",
|
||||
"cognitivesearch",
|
||||
"aisearch",
|
||||
"dotnetCsharp",
|
||||
"azureai",
|
||||
"ai",
|
||||
|
@ -759,7 +759,7 @@
|
|||
"website": "https://github.com/Azure-Samples",
|
||||
"author": "Paul Yuknewicz",
|
||||
"source": "https://github.com/Azure-Samples/function-python-ai-textsummarize",
|
||||
"tags": ["functions", "cognitivesearch", "python", "azureai", "ai", "msft"]
|
||||
"tags": ["functions", "aisearch", "python", "azureai", "ai", "msft"]
|
||||
},
|
||||
{
|
||||
"title": "Flask Container with CDN",
|
||||
|
@ -922,7 +922,7 @@
|
|||
"tags": [
|
||||
"bicep",
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"ai",
|
||||
"apim",
|
||||
"reactjs",
|
||||
|
@ -1049,7 +1049,7 @@
|
|||
"monitor",
|
||||
"keyvault",
|
||||
"appinsights",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"community"
|
||||
]
|
||||
},
|
||||
|
@ -1108,7 +1108,7 @@
|
|||
"openai",
|
||||
"ai",
|
||||
"appservice",
|
||||
"cognitivesearch",
|
||||
"aisearch",
|
||||
"semantickernel",
|
||||
"reactjs",
|
||||
"bicep",
|
||||
|
@ -1143,8 +1143,8 @@
|
|||
"tags": [
|
||||
"ai",
|
||||
"bicep",
|
||||
"chatgpt",
|
||||
"cognitivesearch",
|
||||
"gpt",
|
||||
"aisearch",
|
||||
"javascript",
|
||||
"nodejs",
|
||||
"openai",
|
||||
|
@ -1233,7 +1233,7 @@
|
|||
"website": "https://github.com/Azure-Samples",
|
||||
"author": "Paul Yuknewicz",
|
||||
"source": "https://github.com/Azure-Samples/function-javascript-ai-openai-chatgpt",
|
||||
"tags": ["functions", "openai", "javascript", "ai", "chatgpt", "msft"]
|
||||
"tags": ["functions", "openai", "javascript", "ai", "gpt", "msft"]
|
||||
},
|
||||
{
|
||||
"title": "Azure Functions - Chat using ChatGPT (Python v2 Function)",
|
||||
|
@ -1242,7 +1242,7 @@
|
|||
"website": "https://github.com/Azure-Samples",
|
||||
"author": "Paul Yuknewicz",
|
||||
"source": "https://github.com/Azure-Samples/function-python-ai-openai-chatgpt",
|
||||
"tags": ["functions", "openai", "python", "ai", "chatgpt", "msft"]
|
||||
"tags": ["functions", "openai", "python", "ai", "gpt", "msft"]
|
||||
},
|
||||
{
|
||||
"title": "Azure Functions - LangChain with Azure OpenAI and ChatGPT (Python v2 Function)",
|
||||
|
@ -1262,8 +1262,8 @@
|
|||
"source": "https://github.com/Azure/GPT-RAG",
|
||||
"tags": [
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"cognitivesearch",
|
||||
"gpt",
|
||||
"aisearch",
|
||||
"python",
|
||||
"typescript",
|
||||
"bicep",
|
||||
|
@ -1590,9 +1590,9 @@
|
|||
"python",
|
||||
"typescript",
|
||||
"flask",
|
||||
"cognitivesearch",
|
||||
"aisearch",
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"ai",
|
||||
"msft",
|
||||
"new"
|
||||
|
@ -1625,7 +1625,7 @@
|
|||
"source": "https://github.com/john0isaac/rag-semantic-kernel-mongodb-vcore",
|
||||
"tags": [
|
||||
"openai",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"cosmosdb",
|
||||
"mongodb",
|
||||
"python",
|
||||
|
@ -1645,7 +1645,7 @@
|
|||
"tags": [
|
||||
"ai",
|
||||
"bicep",
|
||||
"chatgpt",
|
||||
"gpt",
|
||||
"serverlessapi",
|
||||
"javascript",
|
||||
"nodejs",
|
||||
|
|
Загрузка…
Ссылка в новой задаче