Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TIDO v5: show panels wrapper which contains text and switch between different types of text content #533

Merged
merged 60 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
30b4ec3
chore: import css files to use default TIDO and tailwind css
Nov 28, 2024
bbf544b
chore: define a basic default config
Nov 28, 2024
1015aa9
feat: add ConfigContext in the App
Nov 28, 2024
9fad0de
chore: use absolute path in the project
Nov 28, 2024
6b1ad4a
chore: movethe configuration of absolute path to tsconfig.json
Nov 28, 2024
72001c8
feat: add text on each panel for each pre-configured panel
Nov 29, 2024
dca9e88
feat: switch the text tab using buttons toggle
Nov 29, 2024
640991e
refactor: create a new component for the Text Switching buttons
Nov 29, 2024
7182af5
chore: remove unneccessary span
Nov 29, 2024
faf367d
chore: add primereact as dev dependency
Dec 2, 2024
8463aae
chore: remove the import of primeicons
Dec 2, 2024
a749063
chore: configure 'single' quotes in eslint config file
Dec 2, 2024
3321f4e
style: convert the 'double' to 'single' quotes
Dec 2, 2024
1b80a18
style: convert the 'double quotes' to 'single quotes' for the PanelsW…
Dec 2, 2024
5c4757e
refactor: define the ConfigProvider as a separate component and updat…
Dec 3, 2024
6dde4f9
refactor: differentiate between collection or manifest by using the a…
Dec 3, 2024
ca6b896
wip(types): add panel config interface
Dec 3, 2024
6cb5a5c
chore: make the config smaller temporarily
Dec 4, 2024
d04af4e
chore: add types in the Panel component
Dec 4, 2024
2be3ab0
chore: add types in ContentTypesToggle component
Dec 4, 2024
35f1192
chore: add further Typescript types to components
Dec 4, 2024
5cb2e44
refactor: add two separate functions getManifestUrl() and getCollecti…
Dec 4, 2024
651b43e
chore: adapt a few things regarding types
Dec 4, 2024
02da22b
chore: add types in CustomHTML component
Dec 4, 2024
9b9a878
refactor: reassign content types by using array map function
Dec 5, 2024
58b7172
style: use tailwind size instead of pixels
Dec 5, 2024
b32c64a
style: rename the textType of item content to contentType
Dec 5, 2024
e67e003
refactor: rewrite the declaration of text - CustomHTML in Panel
Dec 5, 2024
ab35663
wip(loadConfig): accumulate default and custom config
Dec 5, 2024
b4e904a
chore(errorHandling): add an error component
Dec 5, 2024
703f584
chore: add error handling when loading document and item data in Pane…
Dec 6, 2024
6861f14
refactor: move readHtml() and getUrlActiveText() to utils panel file
Dec 6, 2024
f17a8ff
chore: add an example of custom config
Dec 6, 2024
0d3bc07
refactor: use index to toggle between text content types in Panel
Dec 6, 2024
285a19d
chore: restore the value in include in tsconfig
Dec 6, 2024
4f4df05
refactor: remove sass
paulpestov Dec 6, 2024
d331e29
refactor: use ESLint correctly
paulpestov Dec 6, 2024
ad3afca
refactor: update CI script
paulpestov Dec 6, 2024
a16ff7d
style: rename the type for panel config to PanelConfig
Dec 8, 2024
a10a199
refactor: rewrite App component as FC component using an interface fo…
Dec 8, 2024
7bb74d7
chore: remove updateConfig in ConfigContext, instead just use setConfig
Dec 8, 2024
c0f7771
refactor: remove redundant initOpenedPanels()
Dec 9, 2024
30d4c4a
chore: add small eslint fixes
Dec 9, 2024
ed5232c
chore: include error handling in get() which fetches api data
Dec 9, 2024
5d3e22c
refactor: rewrite the logic of getting the item url: 1. we get the ma…
Dec 9, 2024
e925221
feat: introduce error handling for fetch request
Dec 10, 2024
cddbfbc
refactor: remove useEffect in PanelsWrapper() since its not necessary
Dec 10, 2024
8710611
style: remove semicolons
Dec 11, 2024
119d2a6
chore: add widthText as prop to CustomHTML component to show the text…
Dec 11, 2024
fc4caca
refactor: assign only one task to isDataFetchedCorrectly, which retur…
Dec 11, 2024
ee60244
refactor: add try catch in Panel.tsx when receiving the response
Dec 11, 2024
590a149
refactor: rewrite getManifestUrl()
Dec 11, 2024
76c7e42
wip(read Data): restructure readData, use the entrypoint as an object
Dec 11, 2024
a21954b
refactor(read Data): write separate function for reading Manifest and…
Dec 11, 2024
1bccadf
refactor: update http client for type safety
paulpestov Dec 11, 2024
585a342
chore: make app component cleaner
Dec 12, 2024
fdcb737
refactor: use clicked index to update the active content text index
Dec 12, 2024
8728873
refactor: write more compact/pure the function assignContentTypes()
Dec 12, 2024
42c36d5
chore: remove unnecessary function getActiveContentUrl()
Dec 12, 2024
d81f4c0
refactor: update linting rules and code style
paulpestov Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
"compilerOptions": {}
}
38 changes: 33 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
import { FC, useEffect, useState } from "react";
import defaultConfig from "./config";
import "primeicons/primeicons.css";
import { ConfigContext } from "./contexts/ConfigContext";
import Panel from "@/components/panel/Panel";

import { readApi } from "@/utils/http";
import PanelsWrapper from "./components/PanelsWrapper";

function App() {
const [config, setConfig] = useState(defaultConfig);
const [openedPanels, setOpenedPanels] = useState(defaultConfig.panels);

function initOpenedPanels(panels) {
setOpenedPanels((prevValue) => panels);
}
useEffect(() => {
initOpenedPanels(config.panels);
}, []);

return (
<>
<h1>Hi!</h1>
</>
)
<div className="tido">
<ConfigContext.Provider
value={{
config,
setConfig,
openedPanels,
}}
>
<span> Welcome to TIDO</span>
<PanelsWrapper />
</ConfigContext.Provider>
</div>
);
}

export default App
export default App;
11 changes: 11 additions & 0 deletions src/components/CustomHTML.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { useEffect } from "react";
const CustomHTML = ({ textHtml }) => {
const ref = React.useRef();

useEffect(() => {
ref.current.innerHTML = textHtml;
}, [textHtml]);

return <div ref={ref} />;
};
export default CustomHTML;
22 changes: 22 additions & 0 deletions src/components/PanelsWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FC, useState, useEffect, useContext } from "react";
import { ConfigContext } from "@/contexts/ConfigContext";
import Panel from "@/components/panel/Panel";

import { getPanelUrl } from "@/utils/panel";

const PanelsWrapper: FC = ({}) => {
const { config, setConfig, openedPanels } = useContext(ConfigContext);

const panels =
openedPanels.length > 0 &&
openedPanels.map((panel, i) => (
<div key={i} className="t-mr-[25px]">
<Panel url={getPanelUrl(panel)} />
</div>
));
useEffect(() => {}, []);

return <div className="t-flex t-flex-row">{panels}</div>;
};

export default PanelsWrapper;
97 changes: 97 additions & 0 deletions src/components/panel/Panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { FC, useState, useEffect, useContext } from "react";
import { Button } from "primereact/button";

import { ConfigContext } from "@/contexts/ConfigContext";
import CustomHTML from "@/components/CustomHTML";
import TextTypes from "@/components/panel/TextTypes";

import { readApi } from "@/utils/http";

// TODO: add a Typescript interface for the props types
// prop: url - should be the url of collection or manifest
const Panel: FC = ({ url }) => {
const { config, setConfig } = useContext(ConfigContext);
const [data, setData] = useState();
const [itemUrl, setItemUrl] = useState("");
const [text, setText] = useState<React.ReactNode | undefined>();
const [textTypes, setTextTypes] = useState([]);
const [activeText, setActiveText] = useState("");

async function getItemUrl(documentData): string {
paulpestov marked this conversation as resolved.
Show resolved Hide resolved
// if collection - then we should read the api data from the manifest and get its first sequence item id
// if manifest - we retrieve the first sequence item id
if ("title" in documentData) {
// 'title' in document -> document is collection
const manifestData = await readApi(documentData.sequence[0].id);
return manifestData.sequence[0].id;
}

if ("label" in documentData) {
return documentData.sequence[0].id;
}
}

function assignTextTypes(itemData: Item) {
let types: string[] = [];
if (!itemData.hasOwnProperty("content")) return;
if (itemData["content"].length === 0) return;

const content = itemData["content"];
for (let i = 0; i < content.length; i++) {
types.push(getContentType(content[i].type));
}
setTextTypes(() => types);
}

function getContentType(value): string {
paulpestov marked this conversation as resolved.
Show resolved Hide resolved
if (!value) return "";
return value.split("type=")[1];
}

async function readData(url: string) {
const documentData = await readApi(url);
const itemUrl = await getItemUrl(documentData);
const itemData = await readApi(itemUrl);
assignTextTypes(itemData);
const itemHtmlUrl = getUrlActiveText(itemData["content"]);

const textInHtml = await readHtml(itemHtmlUrl);
setText(<CustomHTML textHtml={textInHtml} />);
//setData(documentData);
}

async function readHtml(url: string): Promise<string> {
// url: the url of html file of the item
const data = await fetch(url);
const text = await data.text();

return text;
}

function getUrlActiveText(content) {
const activeItemUrl = content.find((item) =>
item.type.includes(activeText)
).url;
return activeItemUrl;
}

useEffect(() => {
// read Api data from url
readData(url);
}, [url, activeText]);

return (
<div className="panel t-flex t-flex-col t-w-[600px] t-ml-[6%] t-border-solid t-border-2 t-border-slate-200 t-rounded-lg t-mt-[15px] t-px-[10px] t-pt-[150px] t-pb-[25px]">
<div className="t-flex t-flex-col t-items-center t-mb-[25px]">
<TextTypes
textTypes={textTypes}
activeText={activeText}
setActiveText={setActiveText}
/>
</div>
{text}
</div>
);
};

export default Panel;
33 changes: 33 additions & 0 deletions src/components/panel/TextTypes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { FC, useState, useEffect, useContext } from "react";
import { ConfigContext } from "@/contexts/ConfigContext";
import { Button } from "primereact/button";

const TextTypes: FC = ({ textTypes, activeText, setActiveText }) => {
const { config, setConfig, openedPanels } = useContext(ConfigContext);

function handleTextTabClick(e) {
e.preventDefault();
setActiveText(() => e.target.innerHTML);
}

const buttons =
textTypes.length > 0 &&
textTypes.map((type, i) => (
<Button
className="t-p-[5px] t-rounded-[6px]"
style={{ backgroundColor: activeText === type ? "#FFFFFF" : "" }}
key={i}
label={type}
onClick={(e) => handleTextTabClick(e)}
/>
));
useEffect(() => {}, []);

return (
<div className="buttons-text-views t-bg-gray-400 t-p-[3px] t-rounded-[6px] t-h-[35px]">
{buttons}
</div>
);
};

export default TextTypes;
31 changes: 31 additions & 0 deletions src/config.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const defaultConfig = {
globalTree: true,
urlConfig: {},
labels: {
item: "Sheet",
manifest: "Manuscript",
},
colors: {
forceMode: "light",
primary: "#1a3771",
},
panels: [
{
index: 0,
collection:
"https://api.ahiqar.sub.uni-goettingen.de/textapi/ahiqar/syriac/collection.json",
},
{
index: 1,
manifest:
"https://goethes-farbenlehre-berlin.sub.uni-goettingen.de/textapi/Z_1822-02-20_k/manifest.json",
},
{
index: 2,
manifest:
"https://goethes-farbenlehre-berlin.sub.uni-goettingen.de/textapi/ Z_1829-06-28_k/manifest.json",
},
],
};

export default defaultConfig;
3 changes: 3 additions & 0 deletions src/contexts/ConfigContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createContext } from "react";

export const ConfigContext = createContext({});
16 changes: 8 additions & 8 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import { StrictMode } from "react";
paulpestov marked this conversation as resolved.
Show resolved Hide resolved
import { createRoot } from "react-dom/client";
import App from "./App.tsx";

createRoot(document.getElementById('app')!).render(
<StrictMode>
<App />
</StrictMode>,
)
import "./css/preflight.scss";
import "./css/style.css";
import "./css/style.scss";

createRoot(document.getElementById("app")!).render(<App />);
6 changes: 6 additions & 0 deletions src/utils/http.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export async function readApi(url) {
const apiData = await fetch(url);
const data = await apiData.json();

return data;
}
7 changes: 7 additions & 0 deletions src/utils/panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// get the url of the document (collection or manifest) which will be shown in the panel
export function getPanelUrl(panel) {
if (!("collection" in panel) && !("manifest" in panel))
console.error("manifest or collection not defined in panel");
if ("collection" in panel) return panel.collection;
if ("manifest" in panel) return panel.manifest;
}
8 changes: 6 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
Expand All @@ -15,12 +14,17 @@
"noEmit": true,
"jsx": "react-jsx",

"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
"include": ["./"]
paulpestov marked this conversation as resolved.
Show resolved Hide resolved
}