diff --git a/src/components/AboutModal.tsx b/src/components/AboutModal.tsx new file mode 100644 index 0000000..8e3e03f --- /dev/null +++ b/src/components/AboutModal.tsx @@ -0,0 +1,11 @@ +import Page from "./Page" + +const AboutModal: React.FC = () => { + return ( + +

About

+
+ ) +} + +export default AboutModal diff --git a/src/components/GettingStarted.tsx b/src/components/GettingStarted.tsx new file mode 100644 index 0000000..2beac1e --- /dev/null +++ b/src/components/GettingStarted.tsx @@ -0,0 +1,63 @@ +import { BrowserViewLogin, BrowserViewRegister } from "../constants" +import { useBrowserStore, usePersistentStore } from "../store" +import Link from "./Link" + +const GettingStarted = ({ className = "" }) => { + const user = usePersistentStore((state) => state.user) + const setView = useBrowserStore((state) => state.setView) + const needToRegister = !user + const startNumAfterOptionalSteps = needToRegister ? 2 : 1 + return ( +
+
    + {needToRegister ? ( +
  1. + +
    or
    + +
    then
    +
  2. + ) : null} +
  3. + +
    + {startNumAfterOptionalSteps} +
    {" "} + Consult our terms of use + +
  4. +
  5. + +
    + {startNumAfterOptionalSteps + 1} +
    {" "} + Get your API key + +
  6. +
+
+ ) +} + +export default GettingStarted diff --git a/src/components/Link.tsx b/src/components/Link.tsx index c1cfe7a..3563e83 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -3,6 +3,7 @@ interface LinkProps extends React.HTMLProps { children: React.ReactNode className?: string underline?: boolean + disabled?: boolean } const Link: React.FC = ({ @@ -10,16 +11,16 @@ const Link: React.FC = ({ children, className = "", underline = false, + disabled = false, }) => { const href = [import.meta.env.PUBLIC_IMPRESSO_DATALAB_BASE, to] .join("/") .replace(/\/+/g, "/") + const combinedClassName = `${underline ? "text-decoration-underline" : "text-decoration-none"} text-reset ${className} ${disabled ? "disabled" : ""}` + return ( - + {children} ) diff --git a/src/components/Modals.tsx b/src/components/Modals.tsx index bf77c80..60a948a 100644 --- a/src/components/Modals.tsx +++ b/src/components/Modals.tsx @@ -1,9 +1,11 @@ import LoginModal from "./LoginModal" +import RegisterModal from "./RegisterModal" const Modals = () => { return (
+
) } diff --git a/src/components/RegisterForm.tsx b/src/components/RegisterForm.tsx new file mode 100644 index 0000000..35d1369 --- /dev/null +++ b/src/components/RegisterForm.tsx @@ -0,0 +1,233 @@ +import { useEffect, useRef, useState } from "react" +import { Col, Form, Row } from "react-bootstrap" +import UserCard from "./UserCard" +import { + PlanAcademicUser, + PlanImpressoUser, + PlanStudentUser, + PlanLabels, +} from "../constants" + +const Colors: string[] = [ + "#96ceb4", + "#ffeead", + "#ffcc5c", + "#ff6f69", + "#588c7e", + "#f2e394", + "#f2ae72", + "#d96459", + "#a9bdc8", + "#677e96", + "#4a9bb1", + "#ccd6e6", + "#4f615b", + "#3d95a6", + "#d3deec", + "#3c4b54", + "#3e8696", + "#dce5f4", + "#45535f", + "#4a818a", + "#b2bdcc", + "#2e4051", + "#62797d", +] + +const generatePattern = (): string[] => { + const colors = [] + // let palette = Math.floor(Math.random()*this.palettes.length); + for (let i = 0; i < 5; i++) { + const mycolor = Colors[Math.floor(Math.random() * Colors.length)] + colors.push(mycolor) + } + return colors +} + +const Plans = [PlanImpressoUser, PlanStudentUser, PlanAcademicUser] + +export interface RegisterFormPayload { + email: string + password: string + verifyPassword: string + firstname: string + lastname: string + plan: string +} + +export interface RegisterFormProps { + className?: string + onSubmit: (payload: RegisterFormPayload) => void +} + +const RegisterForm: React.FC = ({ className, onSubmit }) => { + const previewDelayTimerRef = useRef(null) + + const [formPreview, setFormPreview] = useState(() => ({ + email: "", + firstname: "-", + lastname: "-", + username: "", + profile: { + pattern: generatePattern(), + }, + isStaff: false, + agreedToTerms: false, + })) + + const formPayload = useRef({ + email: "", + password: "", + verifyPassword: "", + firstname: "-", + lastname: "-", + plan: PlanImpressoUser, + }) + const handleOnSubmit = (e: React.FormEvent) => { + e.preventDefault() + // check errors + console.info("[RegisterForm] @handleOnSubmit") + onSubmit(formPayload.current) + } + const changeProfileColors = (e: React.MouseEvent) => { + e.preventDefault() + console.info("[RegisterForm] @changeProfileColors") + const pattern = generatePattern() + setFormPreview((state) => ({ + ...state, + profile: { + pattern, + }, + pattern: pattern.join(","), + })) + } + + const updateAgreement = (agreedToTerms: boolean) => { + setFormPreview((state) => ({ + ...state, + agreedToTerms, + })) + console.info("[RegisterForm] @updateAgreement", agreedToTerms) + } + + const updatePreview = (key: keyof RegisterFormPayload, value: string) => { + formPayload.current[key] = value + console.info("[RegisterForm] @updatePreview", key, value) + // handpick the fields to preview + previewDelayTimerRef.current = setTimeout(() => { + console.info( + "[RegisterForm] @updatePreview", + "previewing", + formPayload.current, + ) + setFormPreview((state) => ({ + ...state, + pattern: state.profile.pattern.join(","), + email: formPayload.current.email, + firstname: formPayload.current.firstname, + lastname: formPayload.current.lastname, + username: formPayload.current.email, + })) + }, 1000) + } + + useEffect(() => { + return () => { + if (previewDelayTimerRef.current) { + clearTimeout(previewDelayTimerRef.current) + } + } + }, []) + + return ( +
+
+ {Plans.map((plan) => ( + updatePreview("plan", plan)} + id={`ModalRegisterForm.${plan}`} + /> + ))} +
+ + Email address + updatePreview("email", e.target.value)} + type="email" + placeholder="name@example.com" + /> + + + First name + updatePreview("firstname", e.target.value)} + placeholder="your first name" + /> + + + Last name + updatePreview("lastname", e.target.value)} + placeholder="your last name" + /> + + + + + Password + (formPayload.current.password = e.target.value)} + type="password" + /> + + + {/* retype paswword */} + + + + Verify Password + + + (formPayload.current.verifyPassword = e.target.value) + } + type="password" + /> + + + + + updateAgreement(e.target.checked)} + label="I agree to the terms and conditions" + /> + +
+
Preview:
+ + +
+ +
+ ) +} + +export default RegisterForm diff --git a/src/components/RegisterModal.tsx b/src/components/RegisterModal.tsx new file mode 100644 index 0000000..253c222 --- /dev/null +++ b/src/components/RegisterModal.tsx @@ -0,0 +1,51 @@ +import { Modal } from "react-bootstrap" +import { useBrowserStore } from "../store" +import { BrowserViewRegister } from "../constants" +// import { useState } from "react" +// import { type User } from "./UserCard" +import RegisterForm from "./RegisterForm" +import Link from "./Link" + +const RegisterModal = () => { + const view = useBrowserStore((state) => state.view) + const setView = useBrowserStore((state) => state.setView) + // const [candidate, setCandidate] = useState(() => ({ + // username: "", + // isStaff: false, + // firstname: "", + // lastname: "", + // profile: { + // pattern: [], + // }, + // agreedToTerms: false, + // })) + + return ( + setView(null)} + > + + Register + + +

+ Register a new Account to access all features of the Impresso App and + Impresso Datalab.{" "} + + View available Plans + {" "} + to check which one describes best your situation. +

+ + console.info("[RegisterModal] @onSubmit", payload) + } + /> +
+
+ ) +} + +export default RegisterModal diff --git a/src/components/TermsOfUseModal.tsx b/src/components/TermsOfUseModal.tsx new file mode 100644 index 0000000..bda7ef8 --- /dev/null +++ b/src/components/TermsOfUseModal.tsx @@ -0,0 +1,20 @@ +import Page from "./Page" +import { Container, Row } from "react-bootstrap" + +const TermsOfUseModal: React.FC = () => { + return ( + + + +

Terms of Use

+
+
+
+ ) +} + +export default TermsOfUseModal diff --git a/src/components/UserArea.tsx b/src/components/UserArea.tsx index 362594d..67f8882 100644 --- a/src/components/UserArea.tsx +++ b/src/components/UserArea.tsx @@ -4,6 +4,7 @@ import UserCard from "./UserCard" import { userService } from "../services" import { forwardRef, useEffect } from "react" import { PageDown } from "iconoir-react" +import { BrowserViewLogin, BrowserViewRegister } from "../constants" const CustomToggle = forwardRef( ( @@ -11,7 +12,7 @@ const CustomToggle = forwardRef( children?: React.ReactNode onClick: (event: React.MouseEvent) => {} }, - ref: React.Ref + ref: React.Ref, ) => ( - ) + ), ) const UserArea = () => { @@ -42,7 +43,7 @@ const UserArea = () => { if (wsStatus !== "connected") { console.debug( "[UserArea] @useEffect - ws not connected, current status", - wsStatus + wsStatus, ) return } @@ -63,7 +64,7 @@ const UserArea = () => { }) } else { console.debug( - "[UserArea] @useEffect - ws connected, but no token available. Reset user." + "[UserArea] @useEffect - ws connected, but no token available. Reset user.", ) setUser(null) } @@ -90,12 +91,16 @@ const UserArea = () => { - )} diff --git a/src/components/UserCard.tsx b/src/components/UserCard.tsx index fd12062..7df476b 100644 --- a/src/components/UserCard.tsx +++ b/src/components/UserCard.tsx @@ -6,6 +6,7 @@ export interface User { firstname?: string lastname?: string pattern?: string + email?: string profile?: { pattern: string[] } @@ -14,9 +15,16 @@ export interface User { agreedToTerms?: boolean } -const UserCard = ({ user }: { user: User }) => { +const UserCard = ({ + className = "", + user, +}: { + className?: string + user: User +}) => { + console.debug("[UserCard] rendering:", user) return ( -
+
- - + +

- Boost your Media Monitoring + Boost your
+ Media Monitoring

-

+

Explore and work programmatically with the Impresso Corpus, Data and Models

@@ -68,9 +70,8 @@ const Wall = ({ in {numberOfSeries} series, maintained and developed by{" "} {numberOfAuthors} authors.

-
- + The Impresso project (link to project website) strives to create meaningful links across distinct datasets. The Impresso Datalab is an infrastructure for programmatic data access and annotation @@ -95,21 +96,31 @@ const Wall = ({
- - + + + + {seriesTutorials.map((collection) => ( - + ))} - + {seriesYourData.map((collection) => ( - + ))} - - + + ))} diff --git a/src/constants.ts b/src/constants.ts index eaa2054..0ddcdbe 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -77,11 +77,18 @@ export const PlanImpressoUser = "impresso-user" export const PlanStudentUser = "student-user" export const PlanAcademicUser = "academic-user" export const PlanAcademicUserPlus = "academic-user-plus" +export const PlanLabels: Record = { + [PlanGuest]: "Guest", + [PlanImpressoUser]: "No academic affiliation", + [PlanStudentUser]: "Student", + [PlanAcademicUser]: "Academic", + [PlanAcademicUserPlus]: "Academic User Plus", +} export const BrowserViewLogin = "login" -export const BrowserViewSignup = "signup" +export const BrowserViewRegister = "signup" -export const BrowserViews: string[] = [BrowserViewLogin, BrowserViewSignup] +export const BrowserViews: string[] = [BrowserViewLogin, BrowserViewRegister] export const BrowserWsStatusIdle = "idle" export const BrowserWsStatusConnecting = "connecting" diff --git a/src/content/series/enter-impresso-models.mdx b/src/content/series/enter-impresso-models.mdx index 4d5166b..2599429 100644 --- a/src/content/series/enter-impresso-models.mdx +++ b/src/content/series/enter-impresso-models.mdx @@ -1,6 +1,6 @@ --- -title: Working with impresso models on HuggingFace -excerpt: "Process your data the impresso way" +title: Enrich your Data with Impresso Models +excerpt: "Use Impresso’s models for the semantic indexation of your personal data collections " notebooks: - detect-news-agency-with-impresso-model --- diff --git a/src/content/series/enter-impresso.mdx b/src/content/series/enter-impresso.mdx index e62980f..c9707cb 100644 --- a/src/content/series/enter-impresso.mdx +++ b/src/content/series/enter-impresso.mdx @@ -5,4 +5,5 @@ notebooks: - setup --- -Create an Impresso account and learn how to access our API. You can run the notebooks locally or in your preferred environment — whether that's Docker, MyBinder, or Google Colab." +Create an Impresso account and learn how to access our API. +You can run the notebooks locally or in your preferred environment — whether that's Docker, MyBinder, or Google Colab. diff --git a/src/content/series/entities.mdx b/src/content/series/entities.mdx index 324c75a..385a730 100644 --- a/src/content/series/entities.mdx +++ b/src/content/series/entities.mdx @@ -1,6 +1,6 @@ --- -title: Named entities & co. -excerpt: "Detect named entities in your text." +title: Explore and Visualise your Data +excerpt: "Use Impresso notebook templates as starting points for your analysis." notebooks: - generic-entity-api --- diff --git a/src/pages/about.astro b/src/pages/about.astro new file mode 100644 index 0000000..f09d8cf --- /dev/null +++ b/src/pages/about.astro @@ -0,0 +1,10 @@ +--- +import App from "../components/App.astro"; +import AboutModal from "../components/AboutModal"; +import Layout from "../layouts/Layout.astro"; +--- + + + + + \ No newline at end of file diff --git a/src/pages/index.astro b/src/pages/index.astro index 759af56..10e9605 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -6,6 +6,6 @@ import Layout from '../layouts/Layout.astro'; --- - + diff --git a/src/pages/notebooks.astro b/src/pages/notebooks.astro index 0508328..bc761a1 100644 --- a/src/pages/notebooks.astro +++ b/src/pages/notebooks.astro @@ -13,7 +13,7 @@ const notebooksProps = await Promise.all(notebooks.map(async (notebook) => { })) --- - + + + + \ No newline at end of file diff --git a/src/styles/global.css b/src/styles/global.css index a445069..bf5cb31 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -44,6 +44,7 @@ --bs-light: var(--impresso-color-paper); --bs-primary: #ffe587; + --bs-primary-rgb: 255, 229, 135; --secondary-rgb: 138, 93, 232; --secondary: rgb(var(--secondary-rgb)); --tertiary: #e85da0; @@ -89,6 +90,7 @@ --impresso-wght-smallcaps: 580; --impresso-wght-bold: 700; --impresso-wght-medium: 550; + --impresso-wght-extrabold: 900; --impresso-font-size-sm: var(--fs12px); /* EASING */ @@ -113,6 +115,9 @@ --negative-spacer-4: -1.5rem; --negative-spacer-5: -3rem; /* SHADOWS */ + --shadow-xs: rgba(52, 58, 64, 0.1) 0px 10px 15px -3px, + rgba(52, 58, 64, 0.05) 0px 4px 6px -2px; + --shadow-sm: 0 0 0.5rem 0 rgba(0, 0, 0, 0.1); --shadow: 0 0 1rem 0 rgba(0, 0, 0, 0.1); --shadow-lg: 0 0 1.5rem 0 rgba(0, 0, 0, 0.1); @@ -188,6 +193,13 @@ button svg { border: 2px var(--impresso-color-yellow) solid; } +.btn-primary-outline { + --bs-btn-bg: transparent; + --bs-btn-color: var(--impresso-color-yellow); + border: 2px var(--impresso-color-black) solid !important; + box-shadow: var(--shadow-xs); +} + .btn-secondary, .btn-secodary.btn-lg, .btn-secodary.btn-sm { @@ -262,10 +274,19 @@ button.btn-secodary:hover { font-weight: var(--impresso-wght-bold); font-variation-settings: "wght" var(--impresso-wght-bold); } +.font-weight-extrabold { + font-weight: var(--impresso-wght-extrabold); + font-variation-settings: "wght" var(--impresso-wght-extrabold); +} .font-size-inherit { font-size: inherit; } - +.border-radius-sm { + border-radius: var(--impresso-border-radius-sm); +} +.border-radius-lg { + border-radius: var(--impresso-border-radius-lg); +} /* ... */ h1 { font-variation-settings: "wght" var(--impresso-wght-bold);