From d9f690f49f47d6c21c5ebc4df1b2a518a2976b7c Mon Sep 17 00:00:00 2001 From: Daniele Guido Date: Fri, 22 Nov 2024 17:24:03 +0100 Subject: [PATCH] Fix/plans (#56) * add .env.local and .env. to be read from Vite and Astro config Remove local env variables from Makefile * add xxl size for Modal * adapt text for different plans * Create plans.md * Update plans.astro to load content from content page * Update config.ts * Update PlansModal.tsx * Create PlansModalFeatureRow.tsx * Update constants.ts * refine plans * Update Page.tsx --------- Co-authored-by: Daniele Guido <1181642+danieleguido@users.noreply.github.com> --- .gitignore | 1 + Makefile | 4 - astro.config.mjs | 9 +- src/components/Page.tsx | 4 +- src/components/PlansModal.tsx | 219 +++++++++++++----- src/components/PlansModalFeatureRow.tsx | 62 +++++ src/constants.ts | 76 ++++-- src/content/config.ts | 3 +- src/content/pagesContents/plans.md | 7 + src/content/plans/01-guest.mdx | 17 +- ...02-impresso-user.mdx => 02-basic-user.mdx} | 7 +- src/content/plans/03-student-user.mdx | 3 +- src/content/plans/04-academic-user.mdx | 3 +- src/content/plans/05-academic-user-plus.mdx | 3 +- src/pages/plans.astro | 17 +- src/styles/global.css | 26 ++- 16 files changed, 353 insertions(+), 108 deletions(-) create mode 100644 src/components/PlansModalFeatureRow.tsx create mode 100644 src/content/pagesContents/plans.md rename src/content/plans/{02-impresso-user.mdx => 02-basic-user.mdx} (73%) diff --git a/.gitignore b/.gitignore index 13a3f16..545bfba 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ static/data/ src/styles/fonts.css impresso-datalab.code-workspace .env.development +.env.local diff --git a/Makefile b/Makefile index e456440..4cf5674 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,6 @@ run-dev: PUBLIC_GIT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD) \ PUBLIC_BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \ PUBLIC_GIT_REMOTE=$(shell git config --get remote.origin.url) \ - PUBLIC_IMPRESSO_API_PATH="/public-api/v1" \ - PUBLIC_IMPRESSO_WS_API_PATH="/api/socket.io" \ - PUBLIC_IMPRESSO_DATALAB_BASE="/datalab" \ - PUBLIC_IMPRESSO_DATALAB_SITE="https://impresso-project.ch" \ npm run dev build-dev: diff --git a/astro.config.mjs b/astro.config.mjs index f61a6d9..0781c4f 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -3,8 +3,10 @@ import react from "@astrojs/react" import mdx from "@astrojs/mdx" import dotenv from "dotenv" -dotenv.config() - +// load .env.local file, .env.development file, and .env file +dotenv.config({ + path: [".env.local", `.env.${process.env.NODE_ENV}`, ".env"], +}) const WsApiTarget = process.env.PUBLIC_IMPRESSO_WS_API_HOST ?? "http://localhost" const WsApiPath = process.env.PUBLIC_IMPRESSO_WS_API_PATH ?? "/api/socket.io" @@ -14,7 +16,8 @@ const PublicApiTarget = const PublicApiPath = process.env.PUBLIC_IMPRESSO_API_PATH ?? "/public-api/v1" // these values are relevant only when the proxy is used with different paths, e.g; for a local instance of impresso middle layer -const ProxyPublicApiPath = process.env.PUBLIC_IMPRESSO_API_PATH ?? "/public-api/v1" +const ProxyPublicApiPath = + process.env.PUBLIC_IMPRESSO_API_PATH ?? "/public-api/v1" const ProxyWsApiPath = process.env.PUBLIC_IMPRESSO_WS_API_PATH ?? "/api/socket.io" diff --git a/src/components/Page.tsx b/src/components/Page.tsx index 5d8e797..24ab385 100644 --- a/src/components/Page.tsx +++ b/src/components/Page.tsx @@ -6,7 +6,7 @@ interface PageProps extends React.HTMLAttributes { title?: string fullscreen?: string | true | undefined subtitle?: string - size?: ModalProps["size"] + size?: ModalProps["size"] | "xxl" modalBodyClassName?: string modalFooterClassName?: string footer?: React.ReactNode @@ -72,7 +72,7 @@ const Page: React.FC = ({ show={show} onHide={handleClose} backdrop="static" - size={size} + size={size === "xxl" ? "xl" : size} keyboard={false} scrollable > diff --git a/src/components/PlansModal.tsx b/src/components/PlansModal.tsx index 1d36acb..d32483c 100644 --- a/src/components/PlansModal.tsx +++ b/src/components/PlansModal.tsx @@ -11,6 +11,26 @@ import { RequirementsLabels, DataFeatureLabels, RequirementToU, + DataFeatureMetadata, + DataFeatureAudioPublicDomain, + DataFeatureFacsimilesPublicDomain, + DataFeatureTranscriptsPublicDomain, + DataFeatureImages, + DataFeatureImagesPublicDomain, + DataFeatureSemanticEnrichments, + DataFeatureFacsimiles, + DataFeatureAudio, + DataFeatureTranscripts, + ExportFeatureFacsimilesPublicDomain, + ExportFeatureAudioPublicDomain, + ExportFeatureTranscriptsPublicDomain, + ExportFeatureImagesPublicDomain, + ExportFeatureMetadata, + ExportFeatureFacsimiles, + ExportFeatureAudio, + ExportFeatureTranscripts, + ExportFeatureImages, + ExportFeatureSemanticEnrichments, } from "../constants" import { CheckCircleSolid, @@ -22,6 +42,8 @@ import { } from "iconoir-react" import "./PlansModal.css" import PlanFeature from "./PlanFeatureCard" +import MarkdownSnippet from "./MarkdownSnippet" +import PlansModalFeatureRow from "./PlansModalFeatureRow" const BootstrapColumnLayoutForLabels = { lg: 2, @@ -30,9 +52,19 @@ const BootstrapColumnLayoutForLabels = { export type PlansModalProps = { plans: Plan[] + title?: string + modalTitle?: string + content: string + displayFeatures?: boolean } -const PlansModal: React.FC = ({ plans = [] }) => { +const PlansModal: React.FC = ({ + plans = [], + title = "Plans", + modalTitle = "Choose a plan", + content = "Choose the plan that best fits your needs.", + displayFeatures = false, +}) => { const [user, acceptedTermsDate] = usePersistentStore((state) => [ state.user, state.acceptTermsDate, @@ -44,12 +76,18 @@ const PlansModal: React.FC = ({ plans = [] }) => { } return ( + + +

{title}

+ + +
= ({ plans = [] }) => {

{plan.title} {plan.id === useActivePlan ? ( -
+
current plan
) : null} @@ -86,36 +124,39 @@ const PlansModal: React.FC = ({ plans = [] }) => { ))} - {Object.keys(GenericFeatureLabels).map((i) => ( - - - {GenericFeatureLabels[i]} - - {plans.map((plan) => { - const feature = plan.features.find((d) => d.ref === i) - return ( - - {feature ? ( - <> - - {feature.title ? ( -

- ) : null} - - ) : ( - - )} - - ) - })} -
- ))} + {displayFeatures && + Object.keys(GenericFeatureLabels).map((i) => ( + + + {GenericFeatureLabels[i]} + + {plans.map((plan) => { + const feature = plan.features.find((d) => d.ref === i) + return ( + + {feature ? ( + <> + + {feature.title ? ( +

+ ) : null} + + ) : ( + + )} + + ) + })} +
+ ))}
@@ -155,35 +196,95 @@ const PlansModal: React.FC = ({ plans = [] }) => {
-

Data availability

+

Data accessibility

-
- {Object.keys(DataFeatureLabels).map((key, i) => ( - - - - {plans.map((plan) => { - const feature = plan.features.find((d) => d.ref === key) - return ( - - {feature ? : } - - ) - })} - - {i % 2 ? ( + {plans.map((plan) => ( + - + +

+ Access in Impresso App +

+ + +

+ Export / Download Impresso App & Datalab +

+
- ) : null} -
+ + ))} + + + +

Metadata

+ +
+ {/* DataFeatureMetadata */} + + + +

Public Data Domain

+ +
+ {[ + [ + DataFeatureFacsimilesPublicDomain, + ExportFeatureFacsimilesPublicDomain, + ], + [DataFeatureAudioPublicDomain, ExportFeatureAudioPublicDomain], + [ + DataFeatureTranscriptsPublicDomain, + ExportFeatureTranscriptsPublicDomain, + ], + [DataFeatureImagesPublicDomain, ExportFeatureImagesPublicDomain], + ].map(([keyData, keyExport]) => ( + + ))} + + +

Protected Data Domain

+ +
+ {[ + [DataFeatureFacsimiles, ExportFeatureFacsimiles], + [DataFeatureAudio, ExportFeatureAudio], + [DataFeatureTranscripts, ExportFeatureTranscripts], + [DataFeatureImages, ExportFeatureImages], + ].map(([keyData, keyExport]) => ( + ))} + + +

Semantic Enrichments

+ +
+ ) diff --git a/src/components/PlansModalFeatureRow.tsx b/src/components/PlansModalFeatureRow.tsx new file mode 100644 index 0000000..2f20524 --- /dev/null +++ b/src/components/PlansModalFeatureRow.tsx @@ -0,0 +1,62 @@ +import { Xmark } from "iconoir-react" +import { Row, Col } from "react-bootstrap" +import PlanFeatureCard from "./PlanFeatureCard" +import type { Plan } from "./PlanCard" + +const BootstrapColumnLayoutForLabels = { + lg: 2, + className: "very-small", +} + +export type PlansModalFeatureRowProps = { + plans: Plan[] + label: string + featureIds?: string[] + className?: string +} + +const PlansModalFeatureRow: React.FC = ({ + label = "", + featureIds = [], + plans = [], + className = "", +}) => { + return ( + + + {plans.map((plan) => { + return ( + + + {featureIds.map((ref, i) => { + const feature = plan.features.find((f) => f.ref === ref) + const hasBorder = + featureIds.length > 1 && i < featureIds.length - 1 + return ( + + {feature ? ( + + ) : ( + + )} + + ) + })} + + + ) + })} + + ) +} +export default PlansModalFeatureRow diff --git a/src/constants.ts b/src/constants.ts index ef78c63..c0031a5 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -21,12 +21,12 @@ export const Requirements: string[] = [ export const RequirementsLabels: Record = { [RequirementToU]: "Agreement to Terms of Use", - [RequirementImpressoAccount]: "Creation of an Impresso Account", + [RequirementImpressoAccount]: "Impresso Account creation", [RequirementProofStudentEnrollment]: - "Proof of current student enrollment in higher education", + "Proof of enrollement in higher education (for students)", [RequirementProofAcademicAffiliation]: "Proof of academic affiliation", [RequirementDataAccessGranted]: - "Data access requires approval by content provider", + "Account creation request must receive approval from content provider", } export const GenericFeatureExploreAll = "explore-all-features" @@ -77,36 +77,66 @@ export const DataFeatures: string[] = [ DataFeatureSemanticEnrichments, ] +export const ExportFeatureMetadata = "export-metadata" +export const ExportFeatureMetadataPublicDomain = "export-metadata-public-domain" +export const ExportFeatureFacsimiles = "export-facsimiles" +export const ExportFeatureFacsimilesPublicDomain = + "export-facsimiles-public-domain" +export const ExportFeatureAudio = "export-audio" +export const ExportFeatureAudioPublicDomain = "export-audio-public-domain" +export const ExportFeatureTranscripts = "export-transcripts" +export const ExportFeatureTranscriptsPublicDomain = + "export-transcripts-public-domain" +export const ExportFeatureImages = "export-images" +export const ExportFeatureImagesPublicDomain = "export-images-public-domain" +export const ExportFeatureSemanticEnrichments = "export-semantic-enrichments" +export const ExportFeatureSemanticEnrichmentsPublicDomain = + "semantic-enrichments-public-domain" + +export const ExportFeatures: string[] = [ + ExportFeatureMetadataPublicDomain, + ExportFeatureMetadata, + ExportFeatureFacsimilesPublicDomain, + ExportFeatureFacsimiles, + ExportFeatureAudioPublicDomain, + ExportFeatureAudio, + ExportFeatureTranscriptsPublicDomain, + ExportFeatureTranscripts, + ExportFeatureImagesPublicDomain, + ExportFeatureImages, + ExportFeatureSemanticEnrichmentsPublicDomain, + ExportFeatureSemanticEnrichments, +] + export const DataFeatureLabels: Record = { - [DataFeatureMetadata]: "Bibliographic Metadata", - [DataFeatureMetadataPublicDomain]: - "Bibliographic Metadata
public domain", - [DataFeatureFacsimiles]: - "Facsimiles - images of documents created during scanning", - [DataFeatureFacsimilesPublicDomain]: - "Facsimiles - images of documents created during scanning
public domain", - [DataFeatureAudio]: "Audio - mostly spoken word radio, mostly no music", - [DataFeatureAudioPublicDomain]: - "Audio - mostly spoken word radio, mostly no music
public domain", - - [DataFeatureTranscripts]: "Transcripts - e.g. radio speaker notes", - [DataFeatureTranscriptsPublicDomain]: - "Transcripts - e.g. radio speaker notes
public domain", + [DataFeatureMetadata]: + "Metadata (bibliographic, descriptive, technical - public and protected domain)", + [DataFeatureFacsimiles]: "Facsimiles - Protected Domain", + [DataFeatureFacsimilesPublicDomain]: "Facsimiles - Public domain", + [DataFeatureAudio]: "Audio records - Protected Domain", + [DataFeatureAudioPublicDomain]: "Audio records - Public Domain", + + [DataFeatureTranscripts]: "Transcripts - Protected Domain", + [DataFeatureTranscriptsPublicDomain]: "Transcripts - Public Domain", [DataFeatureImages]: - "Images - e.g. those published by newspapers or radio magazines.", + "Images (illustrations, photographs, etc.) - Protected Domain", [DataFeatureImagesPublicDomain]: - "Images - e.g. those published by newspapers or radio magazines
public domain", + "Images (illustrations, photographs, etc.) - Public Domain", [DataFeatureSemanticEnrichments]: - "Semantic enrichments generated by Impresso, e.g. named entities, text reuse clusters, topics, image classification etc.", + "Named entities, text reuse clusters, topics, image classification etc. (for both public and protected data)", [DataFeatureSemanticEnrichmentsPublicDomain]: - "Semantic enrichments generated by Impresso, e.g. named entities, text reuse clusters, topics, image classification etc.
public domain", + "Named entities, text reuse clusters, topics, image classification etc.
Public Domain", } -export const Features: string[] = [...GenericFeatures, ...DataFeatures] +export const Features: string[] = [ + ...GenericFeatures, + ...DataFeatures, + ...ExportFeatures, +] export const PlanGuest = "guest" -export const PlanImpressoUser = "impresso-user" +export const PlanImpressoUser = "basic-user" export const PlanStudentUser = "student-user" export const PlanAcademicUser = "academic-user" export const PlanAcademicUserPlus = "academic-user-plus" diff --git a/src/content/config.ts b/src/content/config.ts index c20e637..dea20e5 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -43,7 +43,7 @@ const plans = defineCollection({ status: z.string().optional(), iconColor: z.string().optional(), icon: z.enum(PlanIcons as any).optional(), - }) + }), ) .optional(), requirements: z.array(z.enum(Requirements as any)), @@ -81,6 +81,7 @@ const pagesContents = defineCollection({ type: "content", schema: z.object({ title: z.string(), + modalTitle: z.string().optional(), excerpt: z.string().optional(), }), }) diff --git a/src/content/pagesContents/plans.md b/src/content/pagesContents/plans.md new file mode 100644 index 0000000..096607e --- /dev/null +++ b/src/content/pagesContents/plans.md @@ -0,0 +1,7 @@ +--- +title: Impresso User Plans +modalTitle: User plans overview +excerpt: Overview of the different user plans available for the Impresso Project +--- + +The Impresso Project is committed to respecting copyright and content provider requirements while maximizing research opportunities. Impresso User Plans reflect this goal, providing access to the Impresso Corpus and enabling different actions based on user status, data copyright restrictions, and content provider permissions. diff --git a/src/content/plans/01-guest.mdx b/src/content/plans/01-guest.mdx index ae2c3ab..7ac8f81 100644 --- a/src/content/plans/01-guest.mdx +++ b/src/content/plans/01-guest.mdx @@ -1,11 +1,24 @@ --- id: guest -title: Guest +title: Guest User icon: basic requirements: - terms-of-use features: - ref: metadata + - ref: export-metadata + + - ref: facsimiles-public-domain + + - ref: audio-public-domain + + - ref: transcripts-public-domain + - ref: export-transcripts-public-domain + + - ref: images-public-domain + + - ref: semantic-enrichments + - ref: export-semantic-enrichments --- -Try the Impresso Web app and the Impresso Datalab with access to public domain data. +The Guest User Plan allows anyone to explore the public domain part of the Impresso Corpus, as well as to access all metadata and semantic enrichments through the Impresso Web App and Datalab, without the need to create an account. diff --git a/src/content/plans/02-impresso-user.mdx b/src/content/plans/02-basic-user.mdx similarity index 73% rename from src/content/plans/02-impresso-user.mdx rename to src/content/plans/02-basic-user.mdx index 2102633..f429128 100644 --- a/src/content/plans/02-impresso-user.mdx +++ b/src/content/plans/02-basic-user.mdx @@ -1,6 +1,6 @@ --- -id: impresso-user -title: Impresso User +id: basic-user +title: Basic User icon: basic features: - ref: explore-all-features @@ -9,6 +9,7 @@ features: - ref: metadata-public-domain - ref: metadata + - ref: export-metadata - ref: facsimiles-public-domain icon: public-domain-only-access-no-download @@ -38,4 +39,4 @@ requirements: - impresso-account --- -Adds the ability to work with personal collections in the Impresso Web App and to access our API via the Datalab. +The Basic User Plan offers access to the public domain part of the Impresso Corpus, some protected domain data, as well as metadata and semantic enrichments. With this plan, users can create, save, and export personal collections. diff --git a/src/content/plans/03-student-user.mdx b/src/content/plans/03-student-user.mdx index 4716b4f..54e370e 100644 --- a/src/content/plans/03-student-user.mdx +++ b/src/content/plans/03-student-user.mdx @@ -9,6 +9,7 @@ features: - ref: metadata-public-domain - ref: metadata + - ref: export-metadata - ref: facsimiles-public-domain icon: public-domain-only-access-no-download @@ -39,4 +40,4 @@ requirements: - proof-of-student-enrollment --- -Adds access to copyright-protected data available to students in higher education. +The Student User Plan provides students with the same benefits as the Basic Plan, along with access to additional protected domain data. diff --git a/src/content/plans/04-academic-user.mdx b/src/content/plans/04-academic-user.mdx index c4c046a..c300016 100644 --- a/src/content/plans/04-academic-user.mdx +++ b/src/content/plans/04-academic-user.mdx @@ -8,6 +8,7 @@ features: - ref: generate-api-keys - ref: metadata-public-domain - ref: metadata + - ref: export-metadata - ref: facsimiles-public-domain icon: public-domain-only-access-no-download @@ -38,4 +39,4 @@ requirements: - proof-of-academic-affiliation --- -Adds access to copyright-protected data available for general research purposes. +The Academic User Plan, available to those with an academic affiliation, includes all benefits of the Basic Plan, with access to an expanded range of protected domain data. diff --git a/src/content/plans/05-academic-user-plus.mdx b/src/content/plans/05-academic-user-plus.mdx index 245519e..4768bac 100644 --- a/src/content/plans/05-academic-user-plus.mdx +++ b/src/content/plans/05-academic-user-plus.mdx @@ -9,6 +9,7 @@ features: - ref: metadata-public-domain - ref: metadata + - ref: export-metadata - ref: facsimiles-public-domain icon: public-domain-only-access-no-download @@ -39,4 +40,4 @@ requirements: - data-access-granted --- -Adds ability to request access to data which requires individual permission. +The Academic User+ Plan offers extended access, including collections that require approval from content providers for an Impresso user account. diff --git a/src/pages/plans.astro b/src/pages/plans.astro index 63950d0..21af246 100644 --- a/src/pages/plans.astro +++ b/src/pages/plans.astro @@ -1,5 +1,5 @@ --- -import { getCollection } from "astro:content" +import { getCollection, getEntry } from "astro:content" import { getRecursivelyEntryData } from "../logic" import App from "../components/App.astro" import Layout from "../layouts/Layout.astro" @@ -17,21 +17,24 @@ const plansProps = await Promise.all(plans.map(async (plan) => { })) -const title = "Plans - Impresso Datalab" -const description = "Overview of the different plans for the Impresso Datalab website" +const pageContent = await getEntry("pagesContents", "plans"); + --- \ No newline at end of file diff --git a/src/styles/global.css b/src/styles/global.css index a13dba2..2a0fa01 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -401,12 +401,36 @@ hr { top: var(--spacer-3-5); } +@media (min-width: 992px) { + .modal-lg, + .modal-xl, + .modal-xxl { + --bs-modal-width: 800px; + } +} @media (min-width: 1024px) { .modal-lg, - .modal-xl { + .modal-xl, + .modal-xxl { --bs-modal-width: 1000px !important; } } +@media (min-width: 1024px) and (max-width: 1600px) { + .modal-xxl { + --bs-modal-width: calc(100% - 50px) !important; + } + .modal-xxl .container { + max-width: 100%; + } +} +@media (min-width: 1600px) { + .modal-xxl { + --bs-modal-width: 1550px !important; + } + .modal-xxl .container { + max-width: 100%; + } +} /* Dropdown menu*/ .dropdown-menu {