diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..f5a3f257e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,22 @@ +# Hopsworks Documentation - Claude Guidance + +## Build Commands +- Build and serve locally: `python -m mkdocs serve` +- Check links: `mkdocs serve & sleep 30 && linkchecker http://127.0.0.1:8000/ && kill $!` +- Install dependencies: `pip install -r requirements-docs.txt` + +## Project Structure +- Documentation source in `/docs` directory +- Navigation defined in `mkdocs.yml` +- CSS customization in `/docs/css/` + +## Style Guidelines +- Use Markdown for all documentation files +- Follow Material Design styling conventions +- Include descriptive alt text for all images +- Create concise, focused pages with clear headings +- Use admonitions for important notes/warnings +- Place new images in appropriate subdirectories under `/docs/assets/images/` +- Maintain consistent navigation structure in `mkdocs.yml` +- Use kebab-case for filenames (e.g., `feature-server.md`) +- Keep code examples concise and well-commented \ No newline at end of file diff --git a/README.md b/README.md index 185f84e56..d1fd3a936 100644 --- a/README.md +++ b/README.md @@ -56,4 +56,9 @@ linkchecker http://127.0.0.1:8000/ # If ok just kill the server kill -9 $SERVER_PID -``` \ No newline at end of file +``` + + +## Maintenance +Always update the robot.txt to desintex previous versions of hopsworks documentation (located in doc/robots.txt) + diff --git a/docs/assets/images/hops-logo.png b/docs/assets/images/hops-logo.png index d3625ae07..20be7f647 100644 Binary files a/docs/assets/images/hops-logo.png and b/docs/assets/images/hops-logo.png differ diff --git a/docs/assets/images/hopsworks-logo.png b/docs/assets/images/hopsworks-logo.png deleted file mode 100644 index 36f20bb12..000000000 Binary files a/docs/assets/images/hopsworks-logo.png and /dev/null differ diff --git a/docs/css/animation.css b/docs/css/animation.css new file mode 100644 index 000000000..62b863634 --- /dev/null +++ b/docs/css/animation.css @@ -0,0 +1,25 @@ +/** + * Styles for background animation + */ + +.hero-section { + position: relative; + overflow: hidden; +} + +.bg-animation-canvas { + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + width: 100vw; /* Use viewport width instead of percentage */ + height: 100%; + z-index: 0; + pointer-events: none; +} + +/* Ensure content sits above the animation */ +.hero-content { + position: relative; + z-index: 1; +} \ No newline at end of file diff --git a/docs/css/custom.css b/docs/css/custom.css index 18236a29f..507dd7dae 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -1,129 +1,1485 @@ -[data-md-color-scheme="hopsworks"] { - --md-primary-fg-color: #1eb382; - --md-secondary-fg-color: #188a64; - --md-tertiary-fg-color: #0d493550; - --md-quaternary-fg-color: #fdfdfd; - --border-radius-variable: 5px; +/* + * Hopsworks Documentation Theme + * This CSS overrides the default MkDocs Material theme to align with Hopsworks product UI + * - NO border radius + * - Light backgrounds with white cards + * - GitHub-inspired UI elements + * - Added dark mode support + */ + +/* Light mode variables */ +:root { + --md-hopsworks-primary: #1eb382; + --md-hopsworks-secondary: #188a64; + --md-hopsworks-text: #333333; + --md-hopsworks-text-light: #666666; + --md-hopsworks-border: #e5e5e5; + --md-hopsworks-background: #f5f5f5; + --md-hopsworks-card-bg: #ffffff; + --md-hopsworks-shadow: 0 0px 0px; + --md-hopsworks-radius: 0px; + --md-hopsworks-code-bg: #f6f8fa; + --md-hopsworks-table-header-bg: #f6f8fa; + --md-hopsworks-inline-code-bg: rgba(188, 188, 188, 0.2); } -.md-footer__inner:not([hidden]) { - display: none; +/* Dark mode variables */ +[data-md-color-scheme="slate"] { + --md-hopsworks-primary: #2be9ac; + --md-hopsworks-secondary: #23bd8e; + --md-hopsworks-text: #e0e0e0; + --md-hopsworks-text-light: #b0b0b0; + --md-hopsworks-border: #444444; + --md-hopsworks-background: #252525; + --md-hopsworks-card-bg: #323232; + --md-hopsworks-shadow: 0 0px 0px rgba(); + --md-hopsworks-code-bg: #404040; + --md-hopsworks-table-header-bg: #313131; + --md-hopsworks-inline-code-bg: rgba(113, 113, 113, 0.3); } -/* Lex did stuff here */ -.svg_topnav { - width: 12px; - filter: invert(100); + +/* Overall page background */ +.md-main, .md-content { + background-color: var(--md-hopsworks-background); } -.svg_topnav:hover { - width: 12px; - filter: invert(10); + +.md-content__inner { + padding-top: 1.8rem; + margin-top: -7px; + /* margin-left: 1.2rem; */ +} + +.md-content__inner > :first-child { + margin-top: 0; +} + +/* Header styling to match Hopsworks app */ +.md-header { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); + box-shadow: 0 0px 0 var(--md-hopsworks-border); + border-bottom: 1px solid var(--md-hopsworks-border); } .md-header[data-md-state="shadow"] { - box-shadow: 0 0 0 0; + box-shadow: 0 0px 0 var(--md-hopsworks-border); +} + +.md-header__title { + color: var(--md-hopsworks-text); + margin-left:0rem !important; +} + +.md-header__button { + color: var(--md-hopsworks-text); +} + +.md-header__button:hover { + color: var(--md-hopsworks-primary); +} + +.md-header__topic .md-ellipsis { + font-weight: 500; +} + +/* Search bar styling */ +.md-search__form { + background-color: var(--md-hopsworks-background); + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); +} + +.md-search__input { + color: var(--md-hopsworks-text); +} + +.md-search__input::placeholder { + color: var(--md-hopsworks-text-light); +} + +.md-search__icon { + color: var(--md-hopsworks-text-light); +} + +/* Fix for white magnifying glass in light theme */ +[data-md-color-scheme="default"] .md-search__icon, +[data-md-color-scheme="hopsworks"] .md-search__icon { + color: #666666; +} + +/* Fix for inconsistent highlighting */ +.md-search-result__link[data-md-state=active] { + background-color: var(--md-hopsworks-background); + background-image: none !important; +} + +.md-search-result__article--document .md-search-result__title { + color: var(--md-hopsworks-text); + font-weight: 500; +} + +.md-search-result__meta { + color: var(--md-hopsworks-text-light); +} + +/* Remove blue gradient from search suggestions */ +.md-search__output { + background-color: var(--md-hopsworks-card-bg); +} + +.md-search-result { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); +} + +.md-search-result__teaser { + color: var(--md-hopsworks-text-light); +} + +/* Navigation tabs */ +.md-tabs { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); + border-top: 1px solid color-mix(in srgb, var(--md-hopsworks-border) 30%, transparent); +} + +.md-tabs__link { + opacity: 0.8; + font-size: 0.75rem; + font-weight: 500; +} + +.md-tabs__link--active, +.md-tabs__link:hover { + color: var(--md-hopsworks-primary); + opacity: 1; +} + + +/* Typography adjustments */ +.md-typeset { + font-size: 0.8rem; + line-height: 1.6; + color: var(--md-hopsworks-text); +} + +.md-typeset h1 { + color: var(--md-hopsworks-text); + font-weight: 600; + font-size: 1.8rem; + margin-top: 0.5rem; + margin-bottom: 1rem; +} + +.md-typeset h2 { + color: var(--md-hopsworks-text); + font-weight: 600; + font-size: 1.4rem; + margin-top: 1rem; + margin-bottom: 0.8rem; +} + +.md-typeset h3 { + color: var(--md-hopsworks-text); + font-weight: 500; + font-size: 1.2rem; + margin-top: 0.8rem; +} + +.md-typeset h4 { + color: var(--md-hopsworks-text); + font-weight: 500; + font-size: 1rem; + margin-top: 0.6rem; +} + +/* Link styling */ +.md-typeset a { + color: var(--md-hopsworks-primary); + text-decoration: none; +} + +.md-typeset a:hover { + text-decoration: underline; +} + +/* Code styling - Enhanced readability */ +.md-typeset code { + background-color: var(--md-hopsworks-inline-code-bg); + border-radius: 3px; /* Slightly rounded corners for inline code */ + padding: 0.2em 0.4em; + font-size: 85%; + color: var(--md-hopsworks-text); +} + +.md-typeset pre > code { + background-color: transparent; + padding: 0.8em 1em; /* More generous padding inside code blocks */ + line-height: 1.5; /* Better line spacing */ + tab-size: 4; /* Consistent tab size */ + color: inherit; +} + +.md-typeset pre { + background-color: var(--md-hopsworks-code-bg); + border: 1px solid var(--md-hopsworks-border); + border-radius: 4px; /* Slightly rounded corners for code blocks */ + margin: 1em 0; /* Consistent vertical spacing */ + padding: 0; /* Remove default padding to control it in code element */ + overflow: auto; /* Ensure horizontal scrolling works well */ + box-shadow: 0 1px 3px rgba(0,0,0,0.05); /* Subtle shadow for depth */ +} + +/* Improve copy button */ +.md-clipboard { + color: var(--md-hopsworks-text-light); + opacity: 0.5; +} + +.md-clipboard:hover { + color: var(--md-hopsworks-primary); + opacity: 1; +} + +/* Table styling - GitHub-inspired */ +.md-typeset table:not([class]) { + font-size: 0.8rem; + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); + box-shadow: none; +} + +.md-typeset table:not([class]) th { + background-color: var(--md-hopsworks-table-header-bg); + color: var(--md-hopsworks-text); + font-weight: 600; + padding: 0.6rem 1rem; +} + +.md-typeset table:not([class]) td { + padding: 0.6rem 1rem; + border-top: 1px solid var(--md-hopsworks-border); +} + +/* Card styling for documentation content */ +.docs-card { + background-color: var(--md-hopsworks-card-bg); + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); + box-shadow: var(--md-hopsworks-shadow); + transition: all 0.2s ease; + margin-top: 0.5rem; +} + +.docs-card:hover { + border-color: var(--md-hopsworks-primary); +} + +.docs-card__title { + font-weight: 600; + margin-top: 0; + font-size: 1.1rem; + margin-bottom: 0.6rem; + color: var(--md-hopsworks-text); +} + +.docs-card__content { + font-size: 0.85rem; + color: var(--md-hopsworks-text-light); +} + +/* Buttons */ +.md-button { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); + font-weight: 500; + transition: all 0.2s ease; +} + +.md-button:hover { + background-color: var(--md-hopsworks-background); + border-color: var(--md-hopsworks-primary); + color: var(--md-hopsworks-text); +} + +.md-button--primary { + background-color: var(--md-hopsworks-primary); + color: var(--md-hopsworks-card-bg); + border-color: var(--md-hopsworks-primary); +} + +.md-button--primary:hover { + background-color: var(--md-hopsworks-secondary); + border-color: var(--md-hopsworks-secondary); + color: var(--md-hopsworks-card-bg); +} + +/* Footer styling */ +.md-footer { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); + border-top: 1px solid var(--md-hopsworks-border); +} + +.md-footer-meta { + background-color: var(--md-hopsworks-background); +} + +/* Admonitions (notes, warnings, etc.) */ +.md-typeset .admonition { + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); + box-shadow: var(--md-hopsworks-shadow); + background-color: var(--md-hopsworks-card-bg); } -.md-tabs__item { - min-width: 2.5rem; +.md-typeset .admonition-title { + font-weight: 600; + background-color: var(--md-hopsworks-background) !important; + background-image: none !important; } -.md-tabs__item:hover { - background-color: var(--md-tertiary-fg-color); - transition: background-color 450ms; +/* Fix admonition icons */ +.md-typeset .admonition-title::before { + color: var(--md-hopsworks-primary); } -.md-sidebar__scrollwrap { - background-color: var(--md-quaternary-fg-color); - padding: 15px 5px 5px 5px; - border-radius: var(--border-radius-variable); +/* Remove blue from details element in dark mode */ +.md-typeset details { + background-color: var(--md-hopsworks-card-bg); + border: 1px solid var(--md-hopsworks-border); + background-image: none !important; +} + +.md-typeset details > summary { + background-color: var(--md-hopsworks-background); + background-image: none !important; +} + +/* Material theme colorscheme override */ +[data-md-color-scheme="default"], +[data-md-color-scheme="hopsworks"] { + --md-primary-fg-color: var(--md-hopsworks-primary); + --md-primary-fg-color--light: var(--md-hopsworks-primary); + --md-primary-fg-color--dark: var(--md-hopsworks-secondary); + --md-accent-fg-color: var(--md-hopsworks-primary); + + /* Override default MkDocs material highlighting */ + --md-accent-bg-color: transparent; + --md-typeset-a-color: var(--md-hopsworks-primary); + --md-typeset-mark-color: rgba(30, 179, 130, 0.1); +} + +[data-md-color-scheme="slate"] { + --md-primary-fg-color: var(--md-hopsworks-primary); + --md-primary-fg-color--light: var(--md-hopsworks-primary); + --md-primary-fg-color--dark: var(--md-hopsworks-secondary); + --md-accent-fg-color: var(--md-hopsworks-primary); + --md-typeset-a-color: var(--md-hopsworks-primary); + + /* Override default MkDocs material highlighting */ + --md-accent-bg-color: transparent; + --md-typeset-mark-color: rgba(43, 233, 172, 0.1); + + /* Fix dark mode blue gradient */ + --md-default-bg-color: var(--md-hopsworks-background); + --md-default-bg-color--light: var(--md-hopsworks-background); + --md-default-bg-color--lighter: var(--md-hopsworks-card-bg); + --md-default-bg-color--lightest: var(--md-hopsworks-card-bg); +} + +/* Light/dark toggle */ +.md-header__button.md-icon { + color: var(--md-hopsworks-text); +} + +.md-header__button.md-icon:hover { + color: var(--md-hopsworks-primary); } .image_logo_02 { - width: 450px; + width: 400px; + height: 200px; + margin: 0 auto; + display: block; +} + +/* Balanced layout for documentation */ +.md-grid { + max-width: 1400px; /* Overall container width */ +} + +/* Main layout structure */ +.md-main__inner { + display: flex; + margin-top: 0; +} + +/* Content area styling */ +.md-content { + max-width: 100%; + flex-grow: 1; + border: none; +} + +/* Content inner container - centered with reasonable width */ +.md-content__inner { + max-width: 50rem; + margin-left: auto; + margin-right: auto; +} + +/* Responsive adjustment */ +@media screen and (max-width: 960px) { + .md-content__inner { + margin-left: 1rem; + margin-right: 1rem; + } +} + +/* Remove sidebar backgrounds and gradients */ + +.md-nav__title, +.md-nav__item--nested .md-nav__toggle ~ .md-nav, +.md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link, +.md-nav--lifted > .md-nav__list > .md-nav__item > .md-nav__link, +.md-nav, +.md-sidebar, +.md-sidebar__scrollwrap, +.md-sidebar .md-nav__container { + background: none !important; + box-shadow: none !important; + background-image: none !important; + border: none !important; +} + +/* Add minimal styling to links */ +.md-nav__link { + color: var(--md-hopsworks-text); +} + +.md-nav__link:hover, +.md-nav__link--active { + color: var(--md-hopsworks-primary); +} + +/* Style top-level section titles in primary sidebar */ +.md-sidebar--primary .md-nav > .md-nav__list > .md-nav__item--nested > .md-nav__link { + font-weight: 500; + color: var(--md-hopsworks-text); + padding-top: 0.75rem; + margin-top: 0.4rem; + border-top: 1px solid rgba(0,0,0,0.07); + font-size: 0.85rem; +} + +[data-md-color-scheme="slate"] .md-sidebar--primary .md-nav > .md-nav__list > .md-nav__item--nested > .md-nav__link { + border-top: 1px solid rgba(255,255,255,0.07); +} + +/* First item doesn't need the top border */ +.md-sidebar--primary .md-nav > .md-nav__list > .md-nav__item--nested:first-child > .md-nav__link { + border-top: none; + margin-top: 0; +} + +/* Hide only the navigation titles in primary sidebar */ +.md-sidebar--primary .md-nav__title, +.md-sidebar--primary .md-nav:not([data-md-level="0"]) > .md-nav__title { + display: none; +} + +/* Style the TOC title */ +.md-sidebar--secondary .md-nav__title { + color: var(--md-hopsworks-text); + font-weight: 500; + padding: 0.75rem 0.8rem; + font-size: 0.85rem; + margin-top: 0.5rem; +} + +/* TOC icon */ +.md-sidebar--secondary .md-nav__title::before { + content: "≡"; + margin-right: 0.5rem; + font-size: 1.2em; + font-weight: bold; + opacity: 0.7; +} + +/* TOC visual hierarchy indicators - simple dot style */ +.md-sidebar--secondary .md-nav__item .md-nav__link { + position: relative; + padding-left: 1.5rem; + margin-left: 0; +} + +/* First level items */ +.md-sidebar--secondary .md-nav__item .md-nav__link::before { + content: "•"; + position: absolute; + left: 0.7rem; + color: var(--md-hopsworks-text); + opacity: 0.8; +} + +/* Nested levels - slight indentation */ +.md-sidebar--secondary .md-nav__item .md-nav__item .md-nav__link { + padding-left: 2.2rem; } -/* End of Lex did stuff here */ +/* Nested level dots */ +.md-sidebar--secondary .md-nav__item .md-nav__item .md-nav__link::before { + content: "◦"; + left: 1.4rem; + opacity: 0.6; +} + +/* Custom version dropdown that appears in the header */ +.md-version-select { + position: relative; + display: flex; + align-items: center; + margin-right: 1.5rem; + cursor: pointer; + font-size: 0.8rem; + font-weight: 500; + color: var(--md-hopsworks-text); + z-index: 1002; +} + +.md-version-current { + display: flex; + align-items: center; + padding: 0.4rem 0.7rem; + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); + background-color: var(--md-hopsworks-background); + transition: all 0.2s ease; +} + +.md-version-current::before { + content: "v"; + display: inline-block; + margin-right: 0.1rem; + font-size: 0.8rem; +} -/* no-icon style for admonitions */ -.md-typeset .no-icon > .admonition-title::before, -.md-typeset .no-icon > summary::before { +.md-version-current::after { + content: "▼"; + display: inline-block; + margin-left: 0.5rem; + font-size: 0.6rem; +} + +.md-version-select:hover .md-version-current { + border-color: var(--md-hopsworks-primary); + color: var(--md-hopsworks-primary); +} + +.md-version-dropdown { + position: absolute; + top: 100%; + left: 0; + min-width: 100%; + margin-top: -4px; display: none; + background-color: var(--md-hopsworks-card-bg); + border: 1px solid var(--md-hopsworks-border); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + border-radius: var(--md-hopsworks-radius); + z-index: 1002; } -.md-typeset .no-icon > :is(.admonition-title, summary) { - padding-left: 1rem; + +.md-version-dropdown a { + display: block; + padding: 0.6rem 0.8rem; + color: var(--md-hopsworks-text); + text-decoration: none; + font-size: 0.8rem; + border-bottom: 1px solid var(--md-hopsworks-border); } -/* end of no-icon style */ -.md-header__button.md-logo { - margin: 0.1rem; - padding: 0.1rem; +.md-version-dropdown a:last-child { + border-bottom: none; } -.md-header__button.md-logo img, -.md-header__button.md-logo svg { +.md-version-dropdown a:hover { + background-color: var(--md-hopsworks-background); + color: var(--md-hopsworks-primary); +} + +.md-version-select:hover .md-version-dropdown { display: block; - width: 1.8rem; - height: 1.8rem; - fill: rgba(43, 155, 70, 0.1); } -.md-tabs { +/* Also include the mike version selector styling for compatibility */ +.md-version { + display: block !important; + position: relative !important; + margin-right: 1rem !important; + z-index: 1002 !important; +} + +.md-version__current { + height: auto !important; +} + + +/* Fix pagination colors */ +.md-footer__link { + color: var(--md-hopsworks-text); +} + +.md-footer__link:hover, +.md-footer__link:focus { + color: var(--md-hopsworks-primary); +} + +/* Remove blue gradient from navigation controls */ +.md-footer__direction { + color: var(--md-hopsworks-text-light); +} + +.md-footer__title { + background-image: none !important; + background-color: transparent !important; +} + +.md-footer__button.md-icon { + background-image: none !important; + background-color: transparent !important; +} + +/* Fix code highlighting inconsistencies */ +.md-typeset code { + background-color: var(--md-hopsworks-inline-code-bg); + color: var(--md-hopsworks-text); +} + +/* Modern Architecture Diagram */ +.platform-architecture { + max-width: 1200px; + margin: 60px auto; + position: relative; + display: flex; + flex-direction: column; + gap: 30px; + padding: 0 20px; +} + +/* For full width pages */ +.md-content__inner.full-width { + max-width: none; + padding-top:0px; + z-index: 1; /* Keep z-index low */ +} + +.architecture-header { + text-align: center; + margin-bottom: 20px; +} + +.arch-title { + font-size: 1.8rem; + font-weight: 600; + margin-bottom: 10px; + color: var(--md-hopsworks-text); +} + +.arch-subtitle { + font-size: 1rem; + color: var(--md-hopsworks-text-light); + margin: 0 auto; + max-width: 700px; + line-height: 1.5; +} + +.architecture-tiers { + display: flex; + gap: 25px; + min-height: 360px; +} + +.architecture-tier { + flex: 1; + display: flex; + flex-direction: column; + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); + border-radius: 0; + box-shadow: none; + transition: all 0.3s ease; +} + +.architecture-tier:hover { + border-color: var(--md-hopsworks-primary); + box-shadow: none; + transform: none; +} + +.tier-header { + padding: 25px 20px; + border-bottom: 1px solid var(--md-hopsworks-border); + background-color: transparent; + border-top-left-radius: var(--md-hopsworks-radius); + border-top-right-radius: var(--md-hopsworks-radius); +} + +.tier-title-container { + display: flex; + align-items: center; + margin-bottom: 8px; +} + +.tier-icon { + font-size: 1.3rem; + margin-right: 10px; + color: var(--md-hopsworks-primary); + display: inline-block; + line-height: 1; + position: relative; + top: 0.1em; +} + +.tier-title { + font-size: 1.2rem; + font-weight: 600; + margin: 0; + color: var(--md-hopsworks-text); +} + +.tier-description { + font-size: 0.9rem; + margin: 5px 0 0 0; + color: var(--md-hopsworks-text-light); + line-height: 1.3; +} + +.tier-components { + flex: 1; + display: flex; + flex-direction: column; + padding: 25px 20px; + gap: 20px; + overflow-y: auto; +} + +.tier-component { + padding: 14px 18px; + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); + border-radius: 0; + transition: all 0.2s ease; +} + +.tier-component:hover { + border-color: var(--md-hopsworks-primary); + transform: none; +} + +.component-title { + font-size: 0.95rem; + font-weight: 500; + margin: 0 0 2px 0; + color: var(--md-hopsworks-text); + line-height: 1.5; + display: flex; + align-items: center; +} + +.component-icon { + color: var(--md-hopsworks-primary); + font-size: 1.1rem; + margin-right: 6px; + display: inline-block; + line-height: 1; + position: relative; + top: 0.05em; +} + +.component-description { + font-size: 0.8rem; + margin: 0; + color: var(--md-hopsworks-text-light); + line-height: 1.3; +} + +/* Responsive adjustments */ +@media (max-width: 960px) { + .architecture-tiers { + flex-direction: column; + min-height: auto; + } + + .feature-grid { + grid-template-columns: repeat(2, 1fr); + } + + .hero-title { + font-size: 2rem !important; + } + + .hero-subtitle { + font-size: 1.1rem; + } +} + +@media (max-width: 600px) { + .feature-grid { + grid-template-columns: 1fr; + } + + .deployment-options { + grid-template-columns: repeat(2, 1fr); + } + + .hero-buttons { + flex-direction: column; + align-items: center; + } + + .hero-button { + width: 80%; + } +} + +/* Hero Section */ +.hero-section { + padding: 80px 20px 70px; + text-align: center; + margin-bottom: 0; + border-bottom: 1px solid var(--md-hopsworks-border); + position: relative; + overflow: hidden; width: 100%; - overflow: auto; - color: var(--md-primary-bg-color); - background-color: var(--md-secondary-fg-color); - transition: background-color 250ms; + left: 0; + right: 0; +} + +.hero-content { + max-width: 900px; + margin: 0 auto; +} + +.hero-title { + font-size: 3rem !important; + font-weight: 600; + margin-bottom: 20px; + color: var(--md-hopsworks-text); + line-height: 1.2; +} + +.hero-subtitle { + font-size: 1.3rem; + color: var(--md-hopsworks-text-light); + margin-bottom: 30px; + line-height: 1.5; + margin-left: auto; + margin-right: auto; +} + +.hero-buttons { + display: flex; + justify-content: center; + gap: 15px; + margin-top: 25px; +} + +.hero-button { + display: inline-block; + padding: 14px 28px; + font-size: 1.1rem; + font-weight: 500; + text-decoration: none; + border-radius: 0; + transition: all 0.2s ease; + box-shadow: none; +} + +.hero-button.primary { + background-color: var(--md-hopsworks-primary); + color: white; + border: 1px solid var(--md-hopsworks-primary); +} + +.hero-button.primary:hover { + background-color: var(--md-hopsworks-secondary); + border-color: var(--md-hopsworks-secondary); +} + +.hero-button.secondary { + background-color: transparent; + color: var(--md-hopsworks-primary); + border: 1px solid var(--md-hopsworks-primary); +} + +.hero-button.secondary:hover { + background-color: var(--md-hopsworks-background); +} + +/* Visual Divider */ +.visual-divider { + max-width: 1200px; + margin: 60px auto; + display: flex; + align-items: center; + justify-content: center; +} + +.divider-line { + height: 1px; + background: linear-gradient(90deg, + transparent 0%, + var(--md-hopsworks-border) 20%, + var(--md-hopsworks-border) 80%, + transparent 100%); + width: 70%; +} + +/* Platform Description */ +.platform-description { + max-width: 1200px; + margin: 60px auto; + text-align: center; + padding: 0 20px; +} + +.description-title { + font-size: 1.8rem; + font-weight: 600; + margin-bottom: 20px; + color: var(--md-hopsworks-text); +} + +.description-text { + font-size: 1.1rem; + color: var(--md-hopsworks-text-light); + line-height: 1.6; + max-width: 900px; + margin: 0 auto; +} + +/* Feature Navigation Grid */ +.feature-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 30px; + margin: 60px auto; + max-width: 1200px; + padding: 0 24px; +} + +.feature-card { + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); + padding: 35px 30px; + transition: all 0.2s ease; + border-radius: 0; + box-shadow: none; + display: flex; + flex-direction: column; +} + +.feature-card:hover { + border-color: var(--md-hopsworks-primary); + transform: none; + box-shadow: none; +} + +.feature-title { + font-size: 1.2rem; + font-weight: 600; + margin-bottom: 12px; + color: var(--md-hopsworks-text); + position: relative; + padding-bottom: 10px; +} + +.feature-title::after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + width: 40px; + height: 3px; + background-color: var(--md-hopsworks-primary); +} + +.feature-description { + font-size: 0.9rem; + color: var(--md-hopsworks-text-light); + margin-bottom: 20px; + line-height: 1.5; + flex-grow: 1; + display: none; /* Hide description */ +} + +/* Adjust spacing after title since descriptions are removed */ +.feature-title { + margin-bottom: 24px !important; + font-weight: 600 !important; + font-size: 1.2rem !important; +} + +.feature-links { + margin-top: auto; +} + +.feature-link { + display: block; + font-size: 0.9rem; + color: var(--md-hopsworks-primary); + margin-bottom: 16px; + text-decoration: none; + transition: all 0.2s ease; + position: relative; + padding-left: 14px; +} + +.feature-link::before { + content: "→"; + position: absolute; + left: -6px; + transition: transform 0.2s ease; +} + +.feature-link:hover { + color: var(--md-hopsworks-secondary); + transform: translateX(2px); +} + +.feature-link:hover::before { + transform: translateX(2px); +} + +/* Deployment Options */ +.deployment-section { + padding: 0 20px; + text-align: center; +} + +.deployment-section-title { + font-size: 1.8rem; + font-weight: 600; + margin-bottom: 15px; + color: var(--md-hopsworks-text); +} + +.deployment-section-description { + font-size: 1.1rem; + color: var(--md-hopsworks-text-light); + margin: 0 auto 40px; } -.wrapper { +.deployment-options { display: grid; grid-template-columns: repeat(4, 1fr); - gap: 10px; - grid-auto-rows: minmax(100px, auto); + gap: 30px; + margin: 0 auto; } -.wrapper * { - border: 2px solid green; +.deployment-option { + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); + padding: 30px 20px; text-align: center; - padding: 70px 0; + transition: all 0.3s ease; + border-radius: 0; + text-decoration: none; } -.one { - grid-column: 1 / 2; - grid-row: 1; +.deployment-option:hover { + border-color: var(--md-hopsworks-primary); + transform: none; + box-shadow: none; } -.two { - grid-column: 2 / 3; - grid-row: 1; + +.cloud-icon { + margin: 0 auto 15px; + display: block; + text-align: center; + height: 50px; + background-color: var(--md-hopsworks-primary); + opacity: 0.1; + transition: all 0.3s ease; } -.three { - grid-column: 3 / 4; - grid-row: 1; + +.deployment-option:hover .cloud-icon { + opacity: 0.2; } -.four { - grid-column: 4 / 5; - grid-row: 1; + +.deployment-title { + font-size: 1rem; + font-weight: 500; + color: var(--md-hopsworks-text); + margin: 0; } -.five { - grid-column: 1 / 3; - grid-row: 2; + +/* Community Section */ +.community-section { + /* Styling handled by deployment-section class */ +} + +.community-links { + display: flex; + justify-content: center; + gap: 30px; +} + +.community-link { + display: flex; + align-items: center; + font-size: 1rem; + color: #666666; /* Dark gray to match magnifying glass in white theme */ + text-decoration: none; + padding: 10px 20px; + border: 1px solid var(--md-hopsworks-border); + border-radius: 0; + transition: all 0.2s ease; +} + +.community-icon { + width: 20px; + height: 20px; + margin-right: 10px; + display: inline-block; + transition: all 0.2s ease; + text-decoration: none; } -.six { - grid-column: 3 / 5; - grid-row: 2; + +/* .community-link:hover .community-icon { + opacity: 0.2; +} */ + +/* .community-link:hover { + border-color: var(--md-hopsworks-primary); + color: var(--md-hopsworks-primary); + transform: none; +} */ + +/* Override footer link styling */ +.md-footer-meta.md-typeset a { + color: #666666 !important; + text-decoration: none !important; +} + +.md-footer-meta { + background-color: var(--md-default-bg-color) !important; +} + +.md-footer-meta.md-typeset a:hover { + color: var(--md-hopsworks-primary) !important; +}.getting-started-section { + margin: 60px auto; + padding: 60px 20px; + text-align: center; + background: linear-gradient(to bottom, var(--md-hopsworks-card-bg), var(--md-hopsworks-background)); + border-top: 1px solid var(--md-hopsworks-border); + border-bottom: 1px solid var(--md-hopsworks-border); +} + +.getting-started-content { + max-width: 1200px; + margin: 0 auto; +} + +.getting-started-title { + font-size: 2rem; + font-weight: 600; + margin-bottom: 12px; + color: var(--md-hopsworks-text); } -/* Jupyter Stuff */ -.jupyter-wrapper .jp-CodeCell .jp-Cell-inputWrapper .jp-InputPrompt { - display: none !important; +.getting-started-description { + font-size: 1.1rem; + color: var(--md-hopsworks-text-light); + margin: 0 auto 30px; } -@media screen and (max-width: 479px) { - .md-sidebar--primary, - .md-sidebar { - z-index: 50 !important; +.steps-timeline { + position: relative; + max-width: 700px; + margin: 40px auto 50px; + padding: 0; + text-align: left; +} + +.timeline-track { + position: absolute; + top: 0; + bottom: 0; + left: 20px; + width: 2px; + background: linear-gradient(to bottom, + var(--md-hopsworks-primary) 0%, + var(--md-hopsworks-primary) 85%, + transparent 100%); + z-index: 1; +} + +.timeline-step { + position: relative; + display: flex; + margin-bottom: 35px; + padding-left: 0; + align-items: center; +} + +.timeline-step:last-child { + margin-bottom: 0; +} + +.timeline-number { + display: flex; + align-items: center; + justify-content: center; + width: 42px; + height: 42px; + background-color: var(--md-hopsworks-primary); + color: white; + border-radius: 0; + font-size: 1.2rem; + font-weight: 600; + margin-right: 16px; + position: relative; + z-index: 2; + box-shadow: none; + flex-shrink: 0; +} + +.timeline-content { + position: relative; + text-align: left; +} + +.timeline-title { + font-size: 1.2rem; + font-weight: 600; + margin: 0 0 4px; + color: var(--md-hopsworks-text); +} + +.timeline-title a { + color: var(--md-hopsworks-text); + text-decoration: none; + transition: color 0.2s ease; +} + +.timeline-title a:hover { + color: var(--md-hopsworks-primary); + text-decoration: none; +} + +.timeline-description { + font-size: 0.95rem; + color: var(--md-hopsworks-text-light); + line-height: 1.4; + margin: 0; +} + +@media (max-width: 600px) { + .timeline-track { + left: 20px; } - .md-logo { - visibility: hidden; + + .timeline-number { + width: 40px; + height: 40px; + font-size: 1.2rem; } } + +.getting-started-buttons { + margin-top: 50px; + text-align: center; +} + +/* Image Zoom Modal */ +.img-modal { + position: fixed; + z-index: 10000; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0, 0, 0, 0.9); + opacity: 0; + visibility: hidden; + transition: opacity 0.3s, visibility 0s 0.3s; + display: none; +} + +.img-modal[style*="display: block"] { + opacity: 1; + visibility: visible; + transition: opacity 0.3s; +} + +/* Modal Content (Image) */ +.modal-content { + margin: auto; + display: block; + max-width: 90%; + max-height: 90vh; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.95); + box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); + transition: transform 0.3s ease; +} + +.img-modal[style*="display: block"] .modal-content { + transform: translate(-50%, -50%) scale(1); +} + +/* Close Button */ +.close-zoom { + position: absolute; + top: 20px; + right: 30px; + color: #f1f1f1; + font-size: 40px; + font-weight: bold; + cursor: pointer; + z-index: 20; + opacity: 0.7; + transition: opacity 0.2s; +} + +.close-zoom:hover { + opacity: 1; +} + +/* Container for images with zoom functionality */ +.zoom-image-container { + position: relative; + display: inline-block; + max-width: 100%; + overflow: hidden; +} + +/* Zoomable images styling */ +img[data-zoomable="true"] { + transition: transform 0.3s ease; + cursor: zoom-in; +} + +.zoom-image-container:hover img[data-zoomable="true"] { + transform: scale(1.02); +} + +/* Zoom indicator for zoomable images */ +.zoom-indicator { + position: absolute; + bottom: 8px; + right: 8px; + width: 32px; + height: 32px; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + opacity: 0; + transition: opacity 0.3s ease, transform 0.3s ease; + pointer-events: none; + font-size: 18px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + z-index: 5; +} + +/* Show zoom indicator on hover */ +.zoom-image-container:hover .zoom-indicator { + opacity: 0.8; + transform: scale(1.1); +} + +/* Loading Spinner for Image Zoom */ +.zoom-loading-spinner { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 50px; + height: 50px; + border: 5px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: white; + animation: spin 1s ease-in-out infinite; + z-index: 5; +} + +@keyframes spin { + to { transform: translate(-50%, -50%) rotate(360deg); } +} + +/* Info text for zoom modal */ +.zoom-info-text { + position: absolute; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + color: rgba(255, 255, 255, 0.7); + background-color: rgba(0, 0, 0, 0.5); + padding: 5px 15px; + border-radius: 20px; + font-size: 14px; + opacity: 0; + transition: opacity 0.5s; +} + +.img-modal:hover .zoom-info-text { + opacity: 1; +} + + + + + +.md-nav__link[href^="http"]:not([href*="docs.hopsworks.ai"])::after { + content: ""; + display: inline-block; + width: 10px; + height: 10px; + margin-left: 4px; + background-image: url('data:image/svg+xml;utf8,'); + background-position: center; + background-repeat: no-repeat; + background-size: contain; +} + +[data-md-color-scheme="slate"] .md-nav__link[href^="http"]:not([href*="docs.hopsworks.ai"])::after { + background-image: url('data:image/svg+xml;utf8,'); +} + +/* External links styling - just dotted underline */ +a[href^="http"]:not([href*="docs.hopsworks.ai"]):not(.md-button):not(.md-logo):not(.md-source) { + border-bottom: 1px dotted var(--md-hopsworks-text-light); +} + +/* Navbar external links */ +.md-tabs__link[href^="http"]:not([href*="docs.hopsworks.ai"]), +.md-nav__link[href^="http"]:not([href*="docs.hopsworks.ai"]) { + border-bottom: 1px dotted var(--md-hopsworks-text-light); +} + +/* Dark mode */ +[data-md-color-scheme="slate"] a[href^="http"]:not([href*="docs.hopsworks.ai"]):not(.md-button):not(.md-logo):not(.md-source), +[data-md-color-scheme="slate"] .md-tabs__link[href^="http"]:not([href*="docs.hopsworks.ai"]), +[data-md-color-scheme="slate"] .md-nav__link[href^="http"]:not([href*="docs.hopsworks.ai"]) { + border-bottom-color: rgba(170, 170, 170, 0.5); +} + + +/* Generic callout-box */ +.callout-box { + padding: 40px 24px; + max-width: 1200px; + margin: 30px auto; +} \ No newline at end of file diff --git a/docs/css/dropdown.css b/docs/css/dropdown.css index c1c768fa2..2a0cc8498 100644 --- a/docs/css/dropdown.css +++ b/docs/css/dropdown.css @@ -1,55 +1,104 @@ -/* Style The Dropdown Button */ -.dropbtn { - color: white; +/* Modal-style API dropdown */ +#api-modal-btn { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: transparent; + color: var(--md-hopsworks-text); + padding: 0.7rem 0rem; /* Match md-tabs__link padding */ + margin: 0; + font-size: 0.75rem; /* Match md-tabs__link font-size */ border: none; cursor: pointer; + font-weight: 500; /* Match md-tabs__link font-weight */ + opacity: 0.8; /* Match the opacity of md-tabs__link */ + transition: opacity, color 0.2s ease; + display: inline-flex; + align-items: center; + gap: 10px; + line-height: 1.6; /* Match md-tabs__link line-height */ } -.md-tabs__list { - contain: inherit; -} -.md-tabs { -overflow: inherit; +/* Down arrow indicator */ +#api-modal-btn::after { + content: ""; + display: inline-block; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid currentColor; + margin-top: 2px; } -.md-header { - z-index: 1000 !important; + +#api-modal-btn:hover { + color: var(--md-hopsworks-primary); + opacity: 1; /* Match the opacity of md-tabs__link:hover */ } -/* The container
- needed to position the dropdown content */ -.dropdown { - position: absolute; - display: inline-block; +/* The dropdown container (no overlay) */ +#api-modal-container { + display: none; + position: fixed; + z-index: 9999; } -/* Dropdown Content (Hidden by Default) */ -.dropdown-content { - display:none; - font-size: 13px; - position: absolute; - background-color: #f9f9f9; - min-width: 160px; +/* Modal content box */ +#api-modal-content { + position: relative; + width: 220px; + background-color: var(--md-hopsworks-card-bg); + border: 1px solid var(--md-hopsworks-border); box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 1000; - border-radius: 2px; - left:-15px; + padding: 0; } -/* Links inside the dropdown */ -.dropdown-content a { - color: black; - padding: 12px 16px; +/* Links inside the modal */ +#api-modal-content a { + color: var(--md-hopsworks-text); + padding: 10px 15px; text-decoration: none; display: block; + font-size: 0.75rem; /* Match navigation font size */ + font-weight: 500; /* Match navigation font weight */ + border-bottom: 1px solid var(--md-hopsworks-border); + transition: background-color 0.2s ease, color 0.2s ease; } -/* Change color of dropdown links on hover */ -.dropdown-content a:hover {background-color: #f1f1f1} +#api-modal-content a:last-child { + border-bottom: none; +} -/* Show the dropdown menu on hover */ -.dropdown:hover .dropdown-content { - display: block; +/* Change color of links on hover */ +#api-modal-content a:hover { + background-color: var(--md-hopsworks-background); + color: var(--md-hopsworks-primary); } -/* Change the background color of the dropdown button when the dropdown content is shown */ -.dropdown:hover .dropbtn { +/* Close button */ +#api-modal-close { + color: var(--md-hopsworks-text-light); + font-size: 1rem; + font-weight: bold; + position: absolute; + top: 5px; + right: 10px; + cursor: pointer; +} + +#api-modal-close:hover { + color: var(--md-hopsworks-text); } + +/* Modal header */ +#api-modal-header { + padding: 10px 15px; + background-color: var(--md-hopsworks-background); + border-bottom: 1px solid var(--md-hopsworks-border); + font-weight: 500; + position: relative; + display: none; /* Hide header to make it look more like a dropdown */ +} + +/* Legacy dropdown classes for compatibility */ +.dropdown, .dropdown-content, .dropbtn { + display: none !important; +} \ No newline at end of file diff --git a/docs/css/marctech.css b/docs/css/marctech.css index 78fddc27e..bf862f347 100644 --- a/docs/css/marctech.css +++ b/docs/css/marctech.css @@ -1,1073 +1,284 @@ -:root { - --md-primary-fg-color: #1EB382; - --md-secondary-fg-color: #188a64; - --md-tertiary-fg-color: #0d493550; - --md-quaternary-fg-color: #fdfdfd; - --md-fiftuary-fg-color: #2471cf; - --border-radius-variable: 5px; - --border-width:1px; -} - -.cellname{ - font-style: italic; - vertical-align: top; - margin-top:-20px; -} -.cellname2{ - font-style: italic; - margin-top:10px; -} - -.marctech_main a{ - color: var(--md-fiftuary-fg-color); - border-bottom: 1px dotted var(--md-fiftuary-fg-color) !important; - text-decoration: dotted !important;} - -.marctech_main a:hover{ - border-bottom: 1px dotted var(--md-primary-fg-color)!important; -} - -.marctech_main a:visited{ - color: var(--md-tertiary-fg-color); - border-bottom: 1px dotted var(--md-tertiary-fg-color) !important; - +/* + * Hopsworks Marketing Styles for Documentation Home Page + * These styles enhance the landing page with more engaging, marketing-focused elements + * while maintaining the clean, professional look of the docs + */ + +/* Getting Started Section Styles */ +.getting-started-section { + background-color: rgba(30, 179, 130, 0.05); + padding: 40px 24px; + margin: 30px auto; + border: 1px solid var(--md-hopsworks-border); + position: relative; } -.w-layout-grid { - display: -ms-grid; - display: grid; - grid-auto-columns: 1fr; - -ms-grid-columns: 1fr 1fr; - grid-template-columns: 1fr 1fr; - -ms-grid-rows: auto auto; - grid-template-rows: auto auto; - grid-row-gap: 16px; - grid-column-gap: 16px; +.getting-started-content { + max-width: 800px; + margin: 0 auto; } -.image_logo{ - width: 69%; - background-color: rgba(255, 255, 255, 0.521); - z-index: 50; - padding: 0px 15px 0px 15px; +.getting-started-title { + font-size: 1.8rem; + font-weight: 600; margin-bottom: 10px; + color: var(--md-hopsworks-text); + text-align: center; } -.layer_02{ - pointer-events: none; -} - -.round-frame{ - pointer-events: initial; +.getting-started-description { + font-size: 1.1rem; + color: var(--md-hopsworks-text-light); + margin-bottom: 30px; + text-align: center; } -.marctech_main { - margin-top:-20px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - margin-bottom: 55px; +.steps-container { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 20px; + margin: 30px 0; } -.collumns { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.step-item { display: flex; - height: 100%; - -webkit-box-align: stretch; - -webkit-align-items: stretch; - -ms-flex-align: stretch; - align-items: stretch; + align-items: flex-start; + gap: 15px; + padding: 15px; + background-color: var(--md-hopsworks-card-bg); + border: 1px solid var(--md-hopsworks-border); + transition: all 0.3s ease; } -.col_heading { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - margin-left: 10px; +.step-item:hover { + border-color: var(--md-hopsworks-primary); + transform: translateY(-3px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); } -.enterprisefs { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.step-number { + width: 30px; + height: 30px; display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; align-items: center; -} - -.enterprise_ai { - -webkit-align-self: center; - -ms-flex-item-align: center; - -ms-grid-row-align: center; - align-self: center; - -webkit-box-flex: 1; - -webkit-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.side-content { - z-index: 0; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - width: 240px; - height: 100%; - margin-top: 10px; - margin-bottom: 10px; - padding: 20px 10px; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - -webkit-align-content: flex-start; - -ms-flex-line-pack: start; - align-content: flex-start; - border-style: solid; - border-width: var(--border-width); - border-color: #585858; - border-radius: 10px; - background-color:var(--md-quaternary-fg-color); -} -.body { - padding: 40px; - font-family: Roboto, sans-serif; -} - -.green { - color: #1eb182; - font-size: 1.2vw; -} - -.rec_frame { - position: relative; - z-index: 1; - display: inline-block; - min-width: 150px; - margin-top: 10px; - margin-right: 10px; - margin-left: 10px; - padding: 10px 10px; - border-style: solid; - border-width: var(--border-width); - border-color: #585858; - border-radius: 10px; - background-color: #fff; - box-shadow: 4px 4px 0 0 rgba(88, 88, 88, 0.16); - -webkit-transition: box-shadow 200ms ease, border-color 200ms ease; - transition: box-shadow 200ms ease, border-color 200ms ease; - color: #585858; - text-align: center; - cursor: pointer; -} - -.rec_frame:hover { - border-color: #c2c2c2; - box-shadow: none; -} - -.name_item { - font-size: 0.7rem; - line-height: 120%; - font-weight: 700; + background-color: var(--md-hopsworks-primary); + color: white; + font-weight: 600; + flex-shrink: 0; } -.name_item.db { - position: relative; - z-index: 3; - text-align: left; +.step-content { + flex: 1; } -.name_item.small { - font-size: 0.6rem; +.step-title { + font-size: 1rem; font-weight: 500; + margin: 0 0 5px 0; + color: var(--md-hopsworks-text); } -.name_item.ingrey { - padding-bottom: 20px; +.step-description { + font-size: 0.9rem; + color: var(--md-hopsworks-text-light); + margin: 0; } -.db_frame-mid { - position: relative; - z-index: 1; - margin-top: -8px; - padding: 5px 2px; - border-style: solid; - border-width: var(--border-width); - border-color: #585858; - border-radius: 0px 0% 50% 50%; - background-color: #fff; - color: #585858; +.getting-started-buttons { + margin-top: 30px; text-align: center; } -.db_frame-top { - position: relative; - z-index: 2; - padding: 5px 2px; - border-style: solid; - border-width: var(--border-width); - border-color: #585858; - border-radius: 50%; - background-color: #fff; - color: #585858; +/* Enhanced Deployment Section */ +.deployment-section { + margin: 40px auto 60px; text-align: center; + padding: 0 20px; } -.icondb { - position: relative; - width: 25px; - min-width: 25px; - margin-right: 10px; -} - -.db_frame { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - width: 150px; - height: 55px; - padding: 20px 10px; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - border-style: solid; - border-width: var(--border-width); - border-color: #585858; - border-radius: 10px; - background-color: #fff; - box-shadow: 4px 4px 0 0 rgba(88, 88, 88, 0.16); - -webkit-transition: box-shadow 200ms ease, border-color 200ms ease; - transition: box-shadow 200ms ease, border-color 200ms ease; - color: #585858; - text-align: center; - cursor: pointer; -} - -.db_frame:hover { - border-color: #c2c2c2; - box-shadow: none; -} - -.grid { - -ms-grid-rows: auto auto auto; - grid-template-rows: auto auto auto; -} - -.arrowdown { - position: relative; - z-index: 0; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - margin-top: -10px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; -} - -.heading_MT { - margin-top: 0px !important; - margin-bottom: 0px !important; - font-size: 1.3rem !important; - white-space: nowrap !important; -} - -.head_col { - padding-left: 10px; -} - -.MT_heading3 { - margin-top: 0px !important ; - font-size: 0.8rem !important; -} - -.MT_heading3.green { - color: #1eb182 !important; -} - -.column_sides { - position: relative; - z-index: 2; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; -} - -.hopsicon { - width: 45px; - height: 45px; -} - -.column_center { - z-index: 10; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; -} - -.center-content { - z-index: -50; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - width: 750px; - height: 670px; - margin-top: 10px; +.deployment-section-title { + font-size: 1.8rem; + font-weight: 600; margin-bottom: 10px; - padding: 20px 10px; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - -webkit-align-content: center; - -ms-flex-line-pack: center; - align-content: center; - border-radius: 10px; - background-color: transparent; + color: var(--md-hopsworks-text); } -.image { - width: 260px; +.deployment-section-description { + font-size: 1.1rem; + color: var(--md-hopsworks-text-light); + margin-bottom: 30px; } -.layer_01 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: stretch; - -webkit-align-items: stretch; - -ms-flex-align: stretch; - align-items: stretch; -} - -.name_center { - font-size: 1rem; - font-weight: 700; +.deployment-description { + font-size: 0.9rem; + color: var(--md-hopsworks-text-light); + margin-top: 8px; } -.rec_frame_main { - position: relative; - z-index: 1; - margin-top: 10px; - margin-right: 10px; - margin-left: 10px; - padding: 5px 10px; - border-style: solid; - border-width: var(--border-width); - border-color: #1eb182; - border-radius: 10px; - background-color: #e6fdf6; - box-shadow: 4px 4px 0 0 #dcf7ee; - -webkit-transition: box-shadow 200ms ease, border-color 200ms ease; - transition: box-shadow 200ms ease, border-color 200ms ease; - color: #1eb182; +/* Community Section */ +.community-section { + margin: 60px auto; text-align: center; - cursor: pointer; -} - -.rec_frame_main:hover { - border-color: #9fecd4; - box-shadow: none; -} - -.rec_frame_main.no_content { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 100%; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - box-shadow: 4px 4px 0 0 #dcf7ee; -} - -.rec_frame_main.no_content:hover { - border-color: #1eb182; - box-shadow: 4px 4px 0 0 rgba(88, 88, 88, 0.16); + padding: 30px 20px; } -.name_item_02 { - font-size: 0.85rem; - font-weight: 700; -} - -.grid-infra { - padding-top: 20px; - -ms-grid-columns: 1fr 1fr 1fr 1fr; - grid-template-columns: 1fr 1fr 1fr 1fr; - -ms-grid-rows: auto; - grid-template-rows: auto; -} - -.rec_frame_main-white { - position: relative; - z-index: 1; - display: inline-block; - width: 100%; - margin-top: 10px; +.community-title { + font-size: 1.5rem; + font-weight: 600; margin-bottom: 10px; - padding: 5px 10px; - border-style: solid; - border-width: var(--border-width); - border-color: #1eb182; - border-radius: 10px; - background-color: #fff; - box-shadow: 4px 4px 0 0 rgba(88, 88, 88, 0.16); - -webkit-transition: box-shadow 200ms ease, border-color 200ms ease; - transition: box-shadow 200ms ease, border-color 200ms ease; - color: #1eb182; - text-align: center; - cursor: pointer; -} - -.rec_frame_main-white:hover { - border-color: #c2c2c2; - box-shadow: none; -} - -.rec_frame_main-white.dotted { - border-style: dotted; -} - -.column { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; - -webkit-box-align: stretch; - -webkit-align-items: stretch; - -ms-flex-align: stretch; - align-items: stretch; + color: var(--md-hopsworks-text); } -.columns_center { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; -} - -.non-bold { - font-weight: 400; +.community-description { + font-size: 1rem; + color: var(--md-hopsworks-text-light); + margin-bottom: 20px; } -.logo-holder { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.community-links { display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; justify-content: center; + gap: 20px; + margin-top: 20px; } -.infra { - text-align: center; - position: relative; - z-index: 30; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - padding: 10px; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - border: 1px dashed #000; - border-radius: 6px; - background-color: #fff; - cursor: pointer; -} - -.infra:hover { - border-style: solid; - border-color: #585858; -} - -.text_and_icon { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.community-link { display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; align-items: center; + gap: 10px; + padding: 12px 20px; + border: 1px solid var(--md-hopsworks-primary); + color: var(--md-hopsworks-text); + text-decoration: none; + transition: all 0.2s ease; } -.svg_icon { - width: 33px; - margin-right: 10px; - margin-left: 10px; -} - -.layer_02 { - position: absolute; - z-index: 10; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - width: 96%; - height: 90%; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: stretch; - -webkit-align-items: stretch; - -ms-flex-align: stretch; - align-items: stretch; - border-style: solid; - border-width: var(--border-width); - border-color: #bbbbbb35 ; - border-radius: 100%; - background-color: transparent; +.community-link:hover { + border-color: var(--md-hopsworks-primary); + background-color: rgba(30, 179, 130, 0.05); + transform: translateY(-2px); } -.round-frame { - position: absolute; - left: 0%; - top: auto; - right: auto; - bottom: 0%; - z-index: 10; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - width: 90px; - height: 90px; - margin: 10px; - padding: 10px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - border-style: dotted; - border-width: var(--border-width); - border-color: var(--md-tertiary-fg-color); - border-radius: 100%; - background-color: #fff; - outline-color: #fffc; - outline-offset: 0px; - outline-style: solid; - outline-width: 4px; - -webkit-transition: box-shadow 200ms ease, border-color 200ms ease; - transition: box-shadow 200ms ease, border-color 200ms ease; - color: var(--md-tertiary-fg-color); - text-align: center; - cursor: pointer; +.community-icon { + width: 20px; + height: 20px; + display: inline-block; + background-color: rgba(30, 179, 130, 0.2); } -.round-frame:hover { - border-color: #c2c2c2; - box-shadow: none; +/* Enhanced Hero Section */ +.hero-section { + border-bottom: 1px solid var(--md-hopsworks-border); } -.round-frame.top-left { - left: 4%; - top: 15%; - right: auto; - bottom: auto; +/* Add third button to hero */ +.hero-buttons { + gap: 12px; } -.round-frame.bottom-left { - left: 4%; - bottom: 15%; +/* Responsive adjustments */ +@media (max-width: 960px) { + .steps-container { + grid-template-columns: repeat(2, 1fr); + } + + .community-links { + flex-direction: column; + align-items: center; + } + + .community-link { + width: 100%; + max-width: 250px; + justify-content: center; + } } -.round-frame.top-right { - left: auto; - top: 15%; - right: 4%; - bottom: auto; +@media (max-width: 600px) { + .steps-container { + grid-template-columns: 1fr; + } + + .step-item { + padding: 12px; + } + + .getting-started-title, + .deployment-section-title, + .community-title { + font-size: 1.5rem; + } + + .getting-started-description, + .deployment-section-description, + .community-description { + font-size: 0.95rem; + } } -.round-frame.bottom-right { - left: auto; - top: auto; - right: 4%; - bottom: 15%; - padding: 10px; +/* Fix for video playlist height matching the main video */ +.getting-started-section .max-w-4xl { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 30px; + margin-top: 40px; } -.side-holder { - z-index: -1; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* Make the playlist column the same height as the video column */ +.getting-started-section .max-w-4xl > div:nth-child(2) { display: flex; - height: 630px; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; flex-direction: column; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; + height: 100%; } -.infra-icon { - width: 25px; - height: 25px; +/* Make the playlist take remaining height */ +.getting-started-section .max-w-4xl > div:nth-child(2) > div:nth-child(2) { + flex-grow: 1; + overflow-y: auto; + height: 0; /* This forces flex-grow to work properly */ } -.div-block { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* Ensure consistent height for video thumbnails */ +.getting-started-section a[href^="https://www.youtube.com/watch"] { display: flex; height: 100%; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; } -#w-node-a2a9b648-f5dd-74e5-e1c2-f7aaf4fa1fcd-46672785 { - -ms-grid-column: span 1; - grid-column-start: span 1; - -ms-grid-column-span: 1; - grid-column-end: span 1; - -ms-grid-row: span 1; - grid-row-start: span 1; - -ms-grid-row-span: 1; - grid-row-end: span 1; -} +/* Other suggested improvements */ -#w-node-_466aa2bf-88bf-5a65-eab4-fc1eb95e7384-46672785 { - -ms-grid-column: span 1; - grid-column-start: span 1; - -ms-grid-column-span: 1; - grid-column-end: span 1; - -ms-grid-row: span 1; - grid-row-start: span 1; - -ms-grid-row-span: 1; - grid-row-end: span 1; +/* Improve readability of feature links */ +.feature-link { + margin-bottom: 10px; + position: relative; + transition: transform 0.2s ease; } -#w-node-_87009ba3-d9a6-e0b7-4cce-581190a19cf3-46672785 { - -ms-grid-column: span 1; - grid-column-start: span 1; - -ms-grid-column-span: 1; - grid-column-end: span 1; - -ms-grid-row: span 1; - grid-row-start: span 1; - -ms-grid-row-span: 1; - grid-row-end: span 1; +.feature-link:hover { + transform: translateX(3px); } -#w-node-_4a479fbb-90c7-9f47-d439-20aa6a224339-46672785 { - -ms-grid-column: span 1; - grid-column-start: span 1; - -ms-grid-column-span: 1; - grid-column-end: span 1; - -ms-grid-row: span 1; - grid-row-start: span 1; - -ms-grid-row-span: 1; - grid-row-end: span 1; +/* Make architecture cards more visually distinct on hover */ +.architecture-tier:hover { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transform: translateY(-2px); + transition: all 0.3s ease; } - -/* - - -inherited from the original template - -*/ - -.w-container .w-row { - margin-left: -10px; - margin-right: -10px; -} -.w-row:before, -.w-row:after { - content: " "; - display: table; - grid-column-start: 1; - grid-row-start: 1; - grid-column-end: 2; - grid-row-end: 2; -} -.w-row:after { - clear: both; -} -.w-row .w-row { - margin-left: 0; - margin-right: 0; -} -.w-col { - position: relative; - float: left; - width: 100%; - min-height: 1px; - padding-left: 10px; - padding-right: 10px; -} -.w-col .w-col { - padding-left: 0; - padding-right: 0; -} -.w-col-1 { - width: 8.33333333%; -} -.w-col-2 { - width: 16.66666667%; -} -.w-col-3 { - width: 25%; -} -.w-col-4 { - width: 33.33333333%; -} -.w-col-5 { - width: 41.66666667%; -} -.w-col-6 { - width: 50%; -} -.w-col-7 { - width: 58.33333333%; -} -.w-col-8 { - width: 66.66666667%; -} -.w-col-9 { - width: 75%; -} -.w-col-10 { - width: 83.33333333%; -} -.w-col-11 { - width: 91.66666667%; -} -.w-col-12 { - width: 100%; -} -.w-hidden-main { - display: none !important; +/* Make component titles more clickable */ +.component-title a { + text-decoration: none; + display: block; + padding: 2px 0; } -@media screen and (max-width: 991px) { - .w-container { - max-width: 728px; - } - .w-hidden-main { - display: inherit !important; - } - .w-hidden-medium { - display: none !important; - } - .w-col-medium-1 { - width: 8.33333333%; - } - .w-col-medium-2 { - width: 16.66666667%; - } - .w-col-medium-3 { - width: 25%; - } - .w-col-medium-4 { - width: 33.33333333%; - } - .w-col-medium-5 { - width: 41.66666667%; - } - .w-col-medium-6 { - width: 50%; - } - .w-col-medium-7 { - width: 58.33333333%; - } - .w-col-medium-8 { - width: 66.66666667%; - } - .w-col-medium-9 { - width: 75%; - } - .w-col-medium-10 { - width: 83.33333333%; - } - .w-col-medium-11 { - width: 91.66666667%; - } - .w-col-medium-12 { - width: 100%; - } - .w-col-stack { - width: 100%; - left: auto; - right: auto; - } -} -@media screen and (max-width: 767px) { - .w-hidden-main { - display: inherit !important; - } - .w-hidden-medium { - display: inherit !important; - } - .w-hidden-small { - display: none !important; - } - .w-row, - .w-container .w-row { - margin-left: 0; - margin-right: 0; - } - .w-col { - width: 100%; - left: auto; - right: auto; - } - .w-col-small-1 { - width: 8.33333333%; - } - .w-col-small-2 { - width: 16.66666667%; - } - .w-col-small-3 { - width: 25%; - } - .w-col-small-4 { - width: 33.33333333%; - } - .w-col-small-5 { - width: 41.66666667%; - } - .w-col-small-6 { - width: 50%; - } - .w-col-small-7 { - width: 58.33333333%; - } - .w-col-small-8 { - width: 66.66666667%; - } - .w-col-small-9 { - width: 75%; - } - .w-col-small-10 { - width: 83.33333333%; - } - .w-col-small-11 { - width: 91.66666667%; - } - .w-col-small-12 { - width: 100%; - } -} -@media screen and (max-width: 479px) { - .column_sides, .layer_02, .enterprisefs{ - visibility: hidden; - } - - .marctech_main { - margin-top: -80px; - } - .grid-infra{ - margin-left: 10px; - margin-right: 10px; - } - .center-content { - width: 100vw; - } - .w-container { - max-width: none; - } - .w-hidden-main { - display: inherit !important; - } - .w-hidden-medium { - display: inherit !important; - } - .w-hidden-small { - display: inherit !important; +/* Improve mobile responsiveness */ +@media (max-width: 767px) { + .getting-started-section .max-w-4xl { + grid-template-columns: 1fr; } - .w-hidden-tiny { - display: none !important; - } - .w-col { - width: 100%; - } - .w-col-tiny-1 { - width: 8.33333333%; - } - .w-col-tiny-2 { - width: 16.66666667%; - } - .w-col-tiny-3 { - width: 25%; - } - .w-col-tiny-4 { - width: 33.33333333%; - } - .w-col-tiny-5 { - width: 41.66666667%; - } - .w-col-tiny-6 { - width: 50%; - } - .w-col-tiny-7 { - width: 58.33333333%; - } - .w-col-tiny-8 { - width: 66.66666667%; - } - .w-col-tiny-9 { - width: 75%; - } - .w-col-tiny-10 { - width: 83.33333333%; - } - .w-col-tiny-11 { - width: 91.66666667%; - } - .w-col-tiny-12 { - width: 100%; + + .hero-title { + font-size: 2.2rem !important; } } \ No newline at end of file diff --git a/docs/images/aws_logo.png b/docs/images/aws_logo.png new file mode 100644 index 000000000..39ff17319 Binary files /dev/null and b/docs/images/aws_logo.png differ diff --git a/docs/images/azure_logo.png b/docs/images/azure_logo.png new file mode 100644 index 000000000..a332cf7bc Binary files /dev/null and b/docs/images/azure_logo.png differ diff --git a/docs/images/gcp_logo.png b/docs/images/gcp_logo.png new file mode 100644 index 000000000..c6f78f7de Binary files /dev/null and b/docs/images/gcp_logo.png differ diff --git a/docs/images/icons8-aws-240.png b/docs/images/icons8-aws-240.png new file mode 100644 index 000000000..c205d2a8a Binary files /dev/null and b/docs/images/icons8-aws-240.png differ diff --git a/docs/images/server_logo.png b/docs/images/server_logo.png new file mode 100644 index 000000000..5ef1e9d98 Binary files /dev/null and b/docs/images/server_logo.png differ diff --git a/docs/index.md b/docs/index.md index 2d72b7ab1..0ff067809 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,281 +3,600 @@ hide: - navigation - toc - title +full_width: true --- -
-
-
-
-
-
-

Enterprise Data

-

Feature Engineering

-
-
-
-
-
Frameworks
-
-
- -
-
- -
-
- -
-
- -
-
-
-
-
Storage connectors
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
+ +
+
+

Hopsworks Documentation

+

Complete guides for building production ML systems with
the Hopsworks AI platform

+ + + +
+

Access Hopsworks from Python

+

+ Install the Hopsworks Python library to interact with the platform from your Python environment. + The Python profile ensures all required dependencies are installed. +

+
+
pip install hopsworks[python]
+
+ + Client Installation Guide + +
+
+
+ + + +
+ + + + +
+

Developer Resources

+ +
+
+ + +
+
+
+
+ + + + + +

Feature Store

+
+

Feature engineering and serving

+
+
+

+ + + + Feature Groups +

+

Organize and version your features

+
+
+

+ + + + + Feature Views +

+

Create training sets and feature vectors

+
+
+

+ + + + Data Validation +

+

Statistics, expectations, and monitoring

-
-
-
-
-
-

Enterprise Feature Store

-
-
-
+
+
+
+ + + + + +

MLOps

+
+

Model management and operations

+
+
+

+ + + + + + Model Registry +

+

Version, store, and manage ML models

-
-
-
-
Govern & Monitor
-
-
-
Serve
-
-
-
Share
& Re-use
-
-
-
Create
-
-
- +
+

+ + + + Model Serving +

+

Deploy models for online and batch inference

+
+
+

+ + + + + + Vector Database +

+

Similarity search and vector embeddings

+
+
+
+
+
+ + + + + +

Infrastructure

+
+

Platform foundation and connectivity

+
+
+

+ + + + Storage Connectors +

+

Connect to external data platforms

+
+
+

+ + + + + Compute Engines +

+

Python, Spark, Flink processing

+
+
+

+ + + + + + + Resource Management +

+

GPU allocation and project governance

+
+
+
+
+
+ + +
+

Hopsworks K8s Installer

+
+

Hopsworks is an enterprise-grade distributed AI Lakehouse platform with a feature store. Deploy a distributed system on your Kubernetes cluster with our installer:

+ + +
+ +
+```bash +curl -O https://raw.githubusercontent.com/logicalclocks/hopsworks-k8s-installer/master/install-hopsworks.py +python3 install-hopsworks.py +``` +
+
+ +
+
+
+

Minimum Requirements:

+
    +
  • Supported Platforms: AWS (EKS), Google Cloud (GKE), Azure (AKS), or OVHCloud
  • +
  • Kubernetes cluster version ≥ 1.27.0
  • +
  • Minimum of 4-5 nodes recommended
  • +
  • Administrative access to your cloud platform
  • +
+

Required Tools:

+
    +
  • Kubernetes CLI (kubectl)
  • +
  • Package manager (helm)
  • +
  • Respective cloud CLI tool (aws/gcloud/az)
  • +
  • Other libraries (boto3, PyYAML)
  • +
+ + + View on GitHub ↗ + +
+ +
+

Enterprise Deployment

+

For production and development deployment of Hopsworks Enterprise, we offer options on global or sovereign clouds with Enterprise SLAs.

+ +

Deployment Options

+
    +
  • Serverless (fastest way to start)
  • +
  • Any cloud provider
  • +
  • On-premises infrastructure
  • +
  • Hybrid setups
  • +
+ + + Hopsworks Serverless + + + Contact for Enterprise License + + + Evaluation License + +
+
+
+ + +
+
+

Hopsworks Academy

+
+ +
+
+ +
+
+

Introduction to ML Systems with Hopsworks

+

Get started with the Hopsworks platform and learn about its core capabilities for ML projects. Learn about best practices for building a modular, composable AI system that will scale with any + use cases for batch, real-time and even large language models.

+
+
+ + + + + Playing Now
-
-
- -
-
-
-
- Write API - - -
-
-
-
-
- Read API - -
-
-
- +
+ +
+
+

Featured Videos

+
+ +
+ + +
+
-
- +
+

Introduction to ML Systems

+

Get started with Hopsworks platform

-
-
-
- - -
Azure
-
+ + + +
+
-
- - -
AWS
-
+
+

Feature Pipelines in Production

+

Code, Deployment & Monitoring

-
- - -
Google Cloud
-
+ + + +
+
-
- - -
On-premise
-
+
+

Real-Time Inference

+

Retrieve Data From Hopsworks

-
-
-
-
-
-
-
-
-

Enterprise AI

-

MLOps

-
+ + + +
+
-
-
-
- -
- -
-
-
- -
+
+

Generating Training Data

+

Training data from the features

-
- - + + + +
+
-
- - +
+

Versioning of Features and Data

+

Different ways to version data and features.

-
+ +
+
+
- - -Hopsworks is a data platform for ML with a Python-centric Feature Store and MLOps capabilities. Hopsworks is a modular platform. You can use it as a standalone Feature Store, you can use it to manage, govern, and serve your models, and you can even use it to develop and operate feature, training and inference pipelines. Hopsworks brings collaboration for ML teams, providing a secure, governed platform for developing, managing, and sharing ML assets - features, models, training data, batch scoring data, logs, and more. - -## Python-Centric Feature Store -Hopsworks is widely used as a standalone Feature Store. Hopsworks breaks the monolithic model development pipeline into separate feature and training pipelines, enabling both feature reuse and better tested ML assets. You can develop features by building feature pipelines in any Python (or Spark or Flink) environment, either inside or outside Hopsworks. You can use the Python frameworks you are familiar with to build production feature pipelines. You can compute aggregations in Pandas, validate feature data with Great Expectations, reduce your data dimensionality with embeddings and PCA, test your feature logic and features end-to-end with PyTest, and transform your categorical and numerical features with Scikit-Learn, TensorFlow, and PyTorch. You can orchestrate your feature pipelines with your Python framework of choice, including Hopsworks' own Airflow support. - -## The Widest Feature Store Capabilities -Hopsworks Feature Store also supports feature pipelines in PySpark, Spark, Flink, and SQL. Offline features can either be stored in Hopsworks, as Hudi tables on object storage, or in external data lakehouses (Snowflake, Databricks, Redshift, BigQuery, any JDBC-enabled platform) via External Feature Groups. Online features are served by [RonDB](https://www.rondb.com), developed by Hopsworks as the lowest latency, highest throughput, highest availability data store for your features. - -## MLOps on Hopsworks -Hopsworks provides model serving capabilities through KServe, with additional support for feature/prediction logging to Kafka (also part of Hopsworks), and secure, low-latency model deployments via Istio. Hopsworks also has a Model Registry for KServe, with support for versioning both models and model assets (such as KServe transformers). Hopsworks also includes a vector database to provide similarity search capabilities for embeddings, based on [OpenSearch](./concepts/mlops/opensearch.md). - -## Project-based Multi-Tenancy and Team Collaboration -Hopsworks provides projects as a secure sandbox in which teams can collaborate and share ML assets. Hopsworks' unique multi-tenant project model even enables sensitive data to be stored in a shared cluster, while still providing fine-grained sharing capabilities for ML assets across project boundaries. Projects can be used to structure teams so that they have end-to-end responsibility from raw data to managed features and models. Projects can also be used to create development, staging, and production environments for data teams. All ML assets support versioning, lineage, and provenance provide all Hopsworks users with a complete view of the MLOps life cycle, from feature engineering through model serving. - -## Development and Operations -Hopsworks provides a FTI (feature/training/inference) pipeline architecture for ML systems. Each part of the pipeline is defined in a Hopsworks job which corresponds to a Jupyter notebook, a python script or a jar. The production pipelines are then orchestrated with Airflow which is bundled in Hopsworks. Hopsworks provides several python environments that can be used and customized for each part of the FTI pipeline, for example switching between using PyTorch or TensorFlow in the training pipeline. You can train models on as many GPUs as are installed in a Hopsworks cluster and easily share them among users. You can also run Spark, Spark Streaming, or Flink programs on Hopsworks. JupyterLab is also bundled which can be used to run Python and Spark interactively. - -## Available on any Platform -Hopsworks is available to be installed on a kubernetes cluster in the cloud on AWS, Azure, and GCP, and On-Prem (Ubuntu/Redhat compatible), even in air-gapped data centers. Hopsworks is also available as a serverless platform that manages and serves both your features and models. - -## Join the community -- Ask questions and give us feedback in the [Hopsworks Community](https://community.hopsworks.ai/) -- Follow us on [Twitter](https://twitter.com/hopsworks) -- Check out all our latest [product releases](https://github.com/logicalclocks/hopsworks/releases) -- Join our public [slack-channel](https://join.slack.com/t/public-hopsworks/shared_invite/zt-24fc3hhyq-VBEiN8UZlKsDrrLvtU4NaA ) - -## Contribute -We are building the most complete and modular ML platform available in the market, and we count on your support to continuously improve Hopsworks. Feel free to [give us suggestions](https://github.com/logicalclocks/hopsworks), [report bugs](https://github.com/logicalclocks/hopsworks/issues) and [add features to our library](https://github.com/logicalclocks/hopsworks-api) anytime. + +
+
+

For Data Engineers

+

Build and optimize feature pipelines

+ +
+ +
+

For Data Scientists

+

Build models using high-quality features

+ +
+ +
+

For MLOps Engineers

+

Deploy and monitor ML systems

+ +
+
-## Open-Source -Hopsworks is available under the AGPL-V3 license. In plain English this means that you are free to use Hopsworks and even build paid services on it, but if you modify the source code, you should also release back your changes and any systems built around it as AGPL-V3. + + -We're the best at what we do, and we strive to keep the same standard for our community! -Our many thanks to the contributors of Hopsworks. diff --git a/docs/js/background-animation.js b/docs/js/background-animation.js new file mode 100644 index 000000000..82ce37798 --- /dev/null +++ b/docs/js/background-animation.js @@ -0,0 +1,186 @@ +/** + * Lightweight background animation with floating nodes + * Only runs on the index page + */ + +document.addEventListener('DOMContentLoaded', function() { + // Only run on the index page - strict check + const currentPath = window.location.pathname; + console.log("Current path:", currentPath); + + // Get the pathname without version part + const pathParts = currentPath.split('/').filter(part => part); + + // Strict check for index paths only + // Should match exactly: /, /index.html, /latest/, /latest/index.html + // And equivalent version paths like /3.0/, /4.0/index.html + const isIndexPath = ( + currentPath === '/' || + currentPath === '/index.html' || + (pathParts.length === 1 && pathParts[0].match(/^(latest|\d+\.\d+)$/)) || + (pathParts.length === 2 && pathParts[0].match(/^(latest|\d+\.\d+)$/) && pathParts[1] === 'index.html') + ); + + if (!isIndexPath) { + console.log("Not on index page, skipping animation"); + return; + } + + console.log("On index page, running animation"); + + // Create canvas element + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + // Add CSS class for styling + canvas.className = 'bg-animation-canvas'; + + // Additional inline styles (these can be moved to CSS if preferred) + canvas.style.opacity = '0.7'; // Increased opacity for visibility + + // Find the hero section and insert the canvas into it + const heroSection = document.querySelector('.hero-section'); + if (heroSection) { + // Make hero section position relative if it's not already + if (getComputedStyle(heroSection).position !== 'relative') { + heroSection.style.position = 'relative'; + } + + // Make sure overflow is hidden + heroSection.style.overflow = 'hidden'; + + // Insert at the beginning of the hero section + heroSection.insertBefore(canvas, heroSection.firstChild); + console.log("Canvas inserted into hero section"); + } else { + console.warn("Hero section not found, inserting into body"); + // Fallback to body insertion + document.body.insertBefore(canvas, document.body.firstChild); + } + + // Resize canvas to full window width + function resizeCanvas() { + // Always use window width to ensure full width + canvas.width = window.innerWidth; + + // Use hero section height if available + if (heroSection) { + canvas.height = heroSection.offsetHeight; + } else { + canvas.height = window.innerHeight; + } + + console.log(`Canvas resized to ${canvas.width}x${canvas.height}`); + } + + // Initialize nodes + const NODES_COUNT = 25; // Increased node count + const nodes = []; + + function initNodes() { + nodes.length = 0; + + for (let i = 0; i < NODES_COUNT; i++) { + nodes.push({ + x: Math.random() * canvas.width, + y: Math.random() * canvas.height, + radius: Math.random() * 4 + 2, // Larger radius for better visibility + speedX: (Math.random() - 0.5) * 0.3, // Slightly faster movement + speedY: (Math.random() - 0.5) * 0.3, + opacity: Math.random() * 0.6 + 0.4, // Higher opacity + rotation: Math.random() * Math.PI * 2, // Random initial rotation + rotationSpeed: (Math.random() - 0.5) * 0.02 // Very slow rotation + }); + } + } + + // Draw nodes and connections + function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Get primary color from CSS variable (Hopsworks green) + const primaryColor = getComputedStyle(document.documentElement) + .getPropertyValue('--md-hopsworks-primary') + .trim() || '#1eb382'; + + // Update and draw nodes + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + + // Move nodes + node.x += node.speedX; + node.y += node.speedY; + + // Update rotation + node.rotation += node.rotationSpeed; + + // Bounce off edges + if (node.x < 0 || node.x > canvas.width) node.speedX *= -1; + if (node.y < 0 || node.y > canvas.height) node.speedY *= -1; + + // Draw node as a rotated square + ctx.save(); + ctx.translate(node.x, node.y); + ctx.rotate(node.rotation); + + ctx.fillStyle = `rgba(${hexToRgb(primaryColor)}, ${node.opacity})`; + ctx.fillRect( + -node.radius, + -node.radius, + node.radius * 2, + node.radius * 2 + ); + + ctx.restore(); + + // Draw connections to nearby nodes + for (let j = i + 1; j < nodes.length; j++) { + const otherNode = nodes[j]; + const dx = node.x - otherNode.x; + const dy = node.y - otherNode.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + // Only connect close nodes + if (distance < 200) { // Increased connection distance + ctx.beginPath(); + ctx.moveTo(node.x, node.y); + ctx.lineTo(otherNode.x, otherNode.y); + // Make lines more visible based on distance + const lineOpacity = (1 - distance / 200) * 0.4; // More visible lines + ctx.strokeStyle = `rgba(${hexToRgb(primaryColor)}, ${lineOpacity})`; + ctx.lineWidth = 1; // Thicker lines + ctx.stroke(); + } + } + } + + requestAnimationFrame(draw); + } + + // Helper function to convert hex to rgb + function hexToRgb(hex) { + // Remove # if present + hex = hex.replace(/^#/, ''); + + // Parse hex components to RGB + const bigint = parseInt(hex, 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + + return `${r}, ${g}, ${b}`; + } + + // Initialize canvas and animation + // Final check - we should only reach this code on the index page + // Only initialize if we have a hero section + if (document.querySelector('.hero-section')) { + window.addEventListener('resize', resizeCanvas); + resizeCanvas(); + initNodes(); + draw(); + console.log("Animation started successfully"); + } else { + console.warn("Hero section not found, animation not started"); + } +}); \ No newline at end of file diff --git a/docs/js/dropdown.js b/docs/js/dropdown.js index 4f0a7e8a7..529b06c7c 100644 --- a/docs/js/dropdown.js +++ b/docs/js/dropdown.js @@ -1,3 +1,131 @@ -document.getElementsByClassName("md-tabs__link")[6].style.display = "none"; -document.getElementsByClassName("md-tabs__link")[8].style.display = "none"; +document.addEventListener('DOMContentLoaded', function() { + // Setup API dropdown without reordering navigation + const tabsContainer = document.querySelector('.md-tabs__list'); + if (!tabsContainer) return; // Safety check + + // Find API navigation item + const apiLinkIndex = Array.from(tabsContainer.children).findIndex(item => + item.textContent.trim().includes('API') + ); + + // Only proceed if we found the API item + if (apiLinkIndex !== -1) { + // Create API dropdown replacement + setupApiDropdown(tabsContainer, apiLinkIndex); + } +}); +/** + * Sets up the API dropdown menu + */ +function setupApiDropdown(tabsContainer, apiLinkIndex) { + // Get the original item to replace + const apiLinkItem = tabsContainer.children[apiLinkIndex]; + + // Create our new modal button + const apiBtn = document.createElement('button'); + apiBtn.id = 'api-modal-btn'; + apiBtn.textContent = 'API'; + apiBtn.setAttribute('type', 'button'); + apiBtn.setAttribute('aria-haspopup', 'true'); + apiBtn.setAttribute('aria-expanded', 'false'); + + // Create a list item to hold the button + const apiListItem = document.createElement('li'); + apiListItem.className = 'md-tabs__item'; + + // Copy height and padding style from original items to maintain consistency + const originalItem = tabsContainer.children[0]; + if (originalItem) { + const computedStyle = window.getComputedStyle(originalItem); + apiListItem.style.height = computedStyle.height; + } + + apiListItem.appendChild(apiBtn); + + // Replace the original API link with our button + tabsContainer.replaceChild(apiListItem, apiLinkItem); + + // Create modal elements + const modalContainer = document.createElement('div'); + modalContainer.id = 'api-modal-container'; + + const modalContent = document.createElement('div'); + modalContent.id = 'api-modal-content'; + + const modalHeader = document.createElement('div'); + modalHeader.id = 'api-modal-header'; + modalHeader.textContent = 'API Documentation'; + + const closeBtn = document.createElement('span'); + closeBtn.id = 'api-modal-close'; + closeBtn.innerHTML = '×'; + modalHeader.appendChild(closeBtn); + + modalContent.appendChild(modalHeader); + + // Add API links + const hopsworksApiLink = document.createElement('a'); + hopsworksApiLink.id = 'hopsworks_api_link'; + hopsworksApiLink.href = 'https://docs.hopsworks.ai/hopsworks-api/latest/generated/api/login/'; + hopsworksApiLink.textContent = 'Hopsworks API'; + modalContent.appendChild(hopsworksApiLink); + + const hsfsJavadocLink = document.createElement('a'); + hsfsJavadocLink.id = 'hsfs_javadoc_link'; + hsfsJavadocLink.href = 'https://docs.hopsworks.ai/hopsworks-api/latest/javadoc'; + hsfsJavadocLink.textContent = 'Feature Store JavaDoc'; + modalContent.appendChild(hsfsJavadocLink); + + modalContainer.appendChild(modalContent); + document.body.appendChild(modalContainer); + + // Position and open modal when button is clicked + apiBtn.addEventListener('click', function(e) { + e.preventDefault(); + + // Toggle dropdown visibility + if (modalContainer.style.display === 'block') { + modalContainer.style.display = 'none'; + apiBtn.setAttribute('aria-expanded', 'false'); + } else { + // Get button position + const rect = apiBtn.getBoundingClientRect(); + + // Position the dropdown right under the button + modalContainer.style.top = (rect.bottom + window.scrollY) + 'px'; + modalContainer.style.left = (rect.left + window.scrollX) + 'px'; + + // Display the dropdown + modalContainer.style.display = 'block'; + apiBtn.setAttribute('aria-expanded', 'true'); + } + + // Prevent event from bubbling to document + e.stopPropagation(); + }); + + // Close when close button is clicked + closeBtn.addEventListener('click', function() { + modalContainer.style.display = 'none'; + apiBtn.setAttribute('aria-expanded', 'false'); + }); + + // Close when clicking anywhere else on the page + document.addEventListener('click', function(e) { + if (modalContainer.style.display === 'block' && + !modalContainer.contains(e.target) && + e.target !== apiBtn) { + modalContainer.style.display = 'none'; + apiBtn.setAttribute('aria-expanded', 'false'); + } + }); + + // Close on escape key + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape' && modalContainer.style.display === 'block') { + modalContainer.style.display = 'none'; + apiBtn.setAttribute('aria-expanded', 'false'); + } + }); +} \ No newline at end of file diff --git a/docs/js/inject-api-links.js b/docs/js/inject-api-links.js index 89082c67d..11fbd7da8 100644 --- a/docs/js/inject-api-links.js +++ b/docs/js/inject-api-links.js @@ -2,27 +2,44 @@ window.addEventListener("DOMContentLoaded", function () { var windowPathNameSplits = window.location.pathname.split("/"); var majorVersionRegex = new RegExp("(\\d+[.]\\d+)"); var latestRegex = new RegExp("latest"); - if (majorVersionRegex.test(windowPathNameSplits[1])) { // On landing page docs.hopsworks.api/4.0 - URL contains major version - // Version API dropdown - document.getElementById("hopsworks_api_link").href = "https://docs.hopsworks.ai/hopsworks-api/" + windowPathNameSplits[1] + "/generated/api/login/"; - document.getElementById("hsfs_javadoc_link").href = "https://docs.hopsworks.ai/hopsworks-api/" + windowPathNameSplits[1] + "/javadoc"; - } else { // on / docs.hopsworks.api/hopsworks-api/4.0 - if (latestRegex.test(windowPathNameSplits[2]) || latestRegex.test(windowPathNameSplits[1])) { - var majorVersion = "latest"; - } else { - var apiVersion = windowPathNameSplits[2]; - var majorVersion = apiVersion.match(majorVersionRegex)[0]; + var majorVersion = "latest"; // Default version + + // Determine the current version from URL + if (majorVersionRegex.test(windowPathNameSplits[1])) { + // On landing page docs.hopsworks.api/4.0 - URL contains major version + majorVersion = windowPathNameSplits[1]; + } else if (!latestRegex.test(windowPathNameSplits[2]) && !latestRegex.test(windowPathNameSplits[1])) { + // If we're not on latest, try to parse version + var apiVersion = windowPathNameSplits[2]; + if (apiVersion && majorVersionRegex.test(apiVersion)) { + majorVersion = apiVersion.match(majorVersionRegex)[0]; + } + } + + // Only update external API links, not navigation links for local development + var hopsworksApiLink = document.getElementById("hopsworks_api_link"); + var hsfsJavadocLink = document.getElementById("hsfs_javadoc_link"); + + if (hopsworksApiLink) { + hopsworksApiLink.href = "https://docs.hopsworks.ai/hopsworks-api/" + majorVersion + "/generated/api/login/"; + } + + if (hsfsJavadocLink) { + hsfsJavadocLink.href = "https://docs.hopsworks.ai/hopsworks-api/" + majorVersion + "/javadoc"; + } + + // Skip updating local navigation links when in development mode + if (window.location.hostname === "docs.hopsworks.ai") { + // Only update links when on the production site + var navLinks = document.getElementsByClassName("md-tabs__link"); + if (navLinks.length >= 7) { + navLinks[0].href = "https://docs.hopsworks.ai/" + majorVersion; + navLinks[1].href = "https://colab.research.google.com/github/logicalclocks/hopsworks-tutorials/blob/master/quickstart.ipynb"; + navLinks[2].href = "https://docs.hopsworks.ai/" + majorVersion + "/tutorials/"; + navLinks[3].href = "https://docs.hopsworks.ai/" + majorVersion + "/concepts/hopsworks/"; + navLinks[4].href = "https://docs.hopsworks.ai/" + majorVersion + "/user_guides/"; + navLinks[5].href = "https://docs.hopsworks.ai/" + majorVersion + "/setup_installation/aws/getting_started/"; + // navLinks[6] is for API, which is handled by dropdown.js } - // Version main navigation - document.getElementsByClassName("md-tabs__link")[0].href = "https://docs.hopsworks.ai/" + majorVersion; - document.getElementsByClassName("md-tabs__link")[1].href = "https://colab.research.google.com/github/logicalclocks/hopsworks-tutorials/blob/master/quickstart.ipynb"; - document.getElementsByClassName("md-tabs__link")[2].href = "https://docs.hopsworks.ai/" + majorVersion + "/tutorials/"; - document.getElementsByClassName("md-tabs__link")[3].href = "https://docs.hopsworks.ai/" + majorVersion + "/concepts/hopsworks/"; - document.getElementsByClassName("md-tabs__link")[4].href = "https://docs.hopsworks.ai/" + majorVersion + "/user_guides/"; - document.getElementsByClassName("md-tabs__link")[5].href = "https://docs.hopsworks.ai/" + majorVersion + "/setup_installation/aws/getting_started/"; - document.getElementsByClassName("md-tabs__link")[6].href = "https://docs.hopsworks.ai/" + majorVersion + "/admin/"; - // Version API dropdown - document.getElementById("hopsworks_api_link").href = "https://docs.hopsworks.ai/hopsworks-api/" + majorVersion + "/generated/api/login/"; - document.getElementById("hsfs_javadoc_link").href = "https://docs.hopsworks.ai/hopsworks-api/" + majorVersion + "/javadoc"; } }); diff --git a/docs/js/layout_improvement.js b/docs/js/layout_improvement.js new file mode 100644 index 000000000..a9d8e54f4 --- /dev/null +++ b/docs/js/layout_improvement.js @@ -0,0 +1,187 @@ +document.addEventListener('DOMContentLoaded', function() { + // Add toggle functionality for the table of contents + const tocSidebar = document.querySelector('.md-sidebar--secondary'); + if (tocSidebar) { + tocSidebar.addEventListener('click', function(e) { + if (e.target === tocSidebar || e.target === tocSidebar.querySelector('::before')) { + if (window.innerWidth >= 1220) { + tocSidebar.classList.toggle('md-sidebar--collapsed'); + } else { + tocSidebar.classList.toggle('md-sidebar--expanded'); + } + } + }); + } + + // Apply full-width class to content area if page has full_width frontmatter + const contentInner = document.querySelector('.md-content__inner'); + if (document.body.hasAttribute('data-full-width')) { + contentInner.classList.add('full-width'); + } + + // Initialize image zoom functionality + initImageZoom(); +}); + +/** + * Image Zoom Functionality + * Makes images in documentation zoomable by clicking on them + */ +function initImageZoom() { + // Create modal container + const modal = document.createElement('div'); + modal.className = 'img-modal'; + modal.setAttribute('role', 'dialog'); + modal.setAttribute('aria-modal', 'true'); + modal.setAttribute('aria-label', 'Image zoom view'); + + // Create modal image + const modalImg = document.createElement('img'); + modalImg.className = 'modal-content'; + modalImg.setAttribute('alt', ''); + + // Create close button + const closeBtn = document.createElement('span'); + closeBtn.className = 'close-zoom'; + closeBtn.innerHTML = '×'; + closeBtn.setAttribute('title', 'Close (Esc)'); + + // Create loading spinner + const spinner = document.createElement('div'); + spinner.className = 'zoom-loading-spinner'; + + // Create help text + const helpText = document.createElement('div'); + helpText.className = 'zoom-info-text'; + helpText.textContent = 'Click or press Esc to close'; + + // Add elements to modal + modal.appendChild(closeBtn); + modal.appendChild(spinner); + modal.appendChild(modalImg); + modal.appendChild(helpText); + + // Add modal to page + document.body.appendChild(modal); + + // Hide spinner when image loads + modalImg.onload = function() { + spinner.style.display = 'none'; + }; + + // Process all suitable images in the document + function processImages() { + // Select all content images + const images = document.querySelectorAll('.md-content img:not([data-zoom-processed])'); + + images.forEach(img => { + // Skip small images, icons and emojis + if (img.complete && (img.naturalWidth < 100 || img.naturalHeight < 100)) { + img.setAttribute('data-zoom-processed', 'skip'); + return; + } + + if (img.classList.contains('twemoji') || + img.classList.contains('emojione') || + img.alt === 'Logo') { + img.setAttribute('data-zoom-processed', 'skip'); + return; + } + + // Mark as zoomable + img.setAttribute('data-zoomable', 'true'); + img.setAttribute('data-zoom-processed', 'true'); + img.style.cursor = 'zoom-in'; + img.title = 'Click to zoom'; + + // Create wrapper and zoom indicator + const parent = img.parentElement; + + // Don't process images that are in links + if (parent.tagName === 'A') { + img.setAttribute('data-zoom-processed', 'skip'); + return; + } + + // Prepare container + let container; + if (parent.tagName !== 'DIV' && parent.tagName !== 'FIGURE' && parent.tagName !== 'P') { + container = document.createElement('div'); + container.className = 'zoom-image-container'; + img.parentNode.insertBefore(container, img); + container.appendChild(img); + } else { + container = parent; + container.classList.add('zoom-image-container'); + } + + // Add zoom indicator + const indicator = document.createElement('div'); + indicator.className = 'zoom-indicator'; + indicator.innerHTML = '🔍'; + container.appendChild(indicator); + + // Add click handler + img.addEventListener('click', function(e) { + e.preventDefault(); + + // Show modal + modal.style.display = 'block'; + + // Show loading spinner while image loads + spinner.style.display = 'block'; + + // Set image source + modalImg.src = this.src; + modalImg.alt = this.alt || ''; + + // Hide spinner if image is already cached + if (modalImg.complete) { + spinner.style.display = 'none'; + } + }); + }); + } + + // Process images initially + processImages(); + + // Set up observer for dynamically loaded content + const observer = new MutationObserver(function(mutations) { + let newContent = false; + mutations.forEach(function(mutation) { + if (mutation.addedNodes.length) { + newContent = true; + } + }); + + if (newContent) { + processImages(); + } + }); + + // Start observing + observer.observe(document.body, { + childList: true, + subtree: true + }); + + // Close modal when clicking X + closeBtn.addEventListener('click', function() { + modal.style.display = 'none'; + }); + + // Close modal when clicking anywhere + modal.addEventListener('click', function(e) { + if (e.target === modal) { + modal.style.display = 'none'; + } + }); + + // Close modal with Escape key + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape' && modal.style.display === 'block') { + modal.style.display = 'none'; + } + }); +} diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 7fc85fb25..1edd0740e 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -5,4 +5,62 @@ Click here to go to latest. +{% endblock %} + +{% block extrahead %} + {{ super() }} + {% if page and page.meta and page.meta.full_width %} + + {% endif %} +{% endblock %} + +{% block scripts %} + {{ super() }} + + + {% endblock %} \ No newline at end of file diff --git a/docs/robots.txt b/docs/robots.txt index a96e321af..a7a6bb0a0 100644 --- a/docs/robots.txt +++ b/docs/robots.txt @@ -1,4 +1,10 @@ User-agent: * -Disallow: +Disallow: / +Allow: /4.1/ +Allow: /latest/ -Sitemap: https://docs.hopsworks.ai/3.2/sitemap.xml \ No newline at end of file +Allow: /hopsworks-api/4.1/ +Allow: /hopsworks-api/latest/ + +Allow: /hopsworks-api/4.1/javadoc/ +Allow: /hopsworks-api/latest/javadoc/ \ No newline at end of file diff --git a/docs/setup_installation/on_prem/contact_hopsworks.md b/docs/setup_installation/on_prem/contact_hopsworks.md index fee9e4600..cca5529a3 100644 --- a/docs/setup_installation/on_prem/contact_hopsworks.md +++ b/docs/setup_installation/on_prem/contact_hopsworks.md @@ -1,11 +1,63 @@ ---- -description: Requirements and instructions on how to install the Hopsworks on-premises. ---- +# Hopsworks Quick Setup Guide -# Hopsworks On-Premise Installation +## Quick Start Script +Get up and running with a single command: +```bash +curl -O https://raw.githubusercontent.com/logicalclocks/hopsworks-k8s-installer/master/install-hopsworks.py +python3 install-hopsworks.py +``` -It is possible to use Hopsworks on-premises, which means that companies can run their machine learning workloads on their own hardware and infrastructure, rather than relying on a cloud provider. This can provide greater flexibility, control, and cost savings, as well as enabling companies to meet specific compliance and security requirements. +## Essential Information +Hopsworks is an enterprise-grade distributed AI Lakehouse platform with a feature store. Currently supports: -Working on-premises with Hopsworks typically involves collaboration with the Hopsworks engineering teams, as each infrastructure is unique and requires a tailored approach to deployment and configuration. The process begins with an assessment of the company's existing infrastructure and requirements, including network topology, security policies, and hardware specifications. +* Amazon Web Services (EKS) -For further details about on-premise installations; [contact us](https://www.hopsworks.ai/contact). +* Google Cloud Platform (GKE) + +* Microsoft Azure (AKS) + +* OVHCloud + +## Technical Requirements + +* Kubernetes cluster version ≥ 1.27.0 + +* 4-5 nodes minimum + +* Required tools: + * kubectl + * helm + * Cloud CLI (aws/gcloud/az) + +## For the Startups and Enthusiasts +Want to dive deeper? Here's what you need: + +### Default Setup + +* AWS: m6i.2xlarge instances, EBS GP3 storage + +* GCP: n2-standard-8 instances + +* Azure: Standard_D8_v4 instances + +### Access Points +Once installed, find your services at: + +* UI: https://:28181 + +* API: https://:8182 + +* Default login: admin@hopsworks.ai / admin + +## Enterprise & Production +For enterprise deployment, including: + +* Production environments + +* Custom configurations + +* Enterprise SLAs + +* Sovereign cloud options + +[Contact our team](https://www.hopsworks.ai/contact) for enterprise deployment options. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index d8cdaf8a2..3b6b988ad 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,23 +1,20 @@ site_name: "Hopsworks Documentation" -site_description: "Official documentation for Hopsworks and its Feature Store - an open source data-intensive AI platform used for the development and operation of machine learning models at scale." +site_description: "Official documentation for Hopsworks AI Lakehouse and Feature Store - A data-intensive AI platform used for the development and operation of machine learning models at scale." site_author: "Hopsworks" site_url: "https://docs.hopsworks.ai/" +use_directory_urls: true # Repository -repo_name: logicalclocks/hopsworks -repo_url: https://github.com/logicalclocks/hopsworks -edit_uri: "" +# No repository link strict: false nav: - - Home: index.md - - Getting Started ↗: https://colab.research.google.com/github/logicalclocks/hopsworks-tutorials/blob/master/quickstart.ipynb + - index.md - Tutorials: - tutorials/index.md - Concepts: - Hopsworks Platform: concepts/hopsworks.md - - MLOps Dictionary ↗: https://www.hopsworks.ai/mlops-dictionary?utm_source=web&utm_medium=docs - Feature Store: - Architecture: concepts/fs/index.md #hsfs - Feature Groups: @@ -244,27 +241,41 @@ nav: - Access Audit Logs: setup_installation/admin/audit/audit-logs.md - Export Audit Logs: setup_installation/admin/audit/export-audit-logs.md - : https://docs.hopsworks.ai - - Community ↗: https://community.hopsworks.ai/ + - Serverless ↗: https://app.hopsworks.ai + - Community ↗: https://community.hopsworks.ai?utm_source=web&utm_medium=docs + - Dictionary ↗: https://www.hopsworks.ai/mlops-dictionary?utm_source=web&utm_medium=docs theme: name: material custom_dir: docs/overrides favicon: assets/images/favicon.ico logo: assets/images/hops-logo.png - icon: - repo: fontawesome/brands/github font: text: "Roboto" code: "IBM Plex Mono" palette: - accent: teal - scheme: hopsworks + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: hopsworks + accent: teal + toggle: + icon: material/brightness-7 + name: Switch to dark mode + + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + accent: teal + toggle: + icon: material/brightness-4 + name: Switch to light mode features: - navigation.tabs - navigation.tabs.sticky - navigation.sections - navigation.indexes - + - content.code.copy + extra: hopsworks_version: dev version: @@ -274,14 +285,12 @@ extra: social: - icon: fontawesome/brands/twitter link: https://twitter.com/hopsworks - - icon: fontawesome/brands/github - link: https://github.com/logicalclocks/hopsworks - icon: fontawesome/brands/discourse link: https://community.hopsworks.ai/ - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/company/hopsworks/ - icon: fontawesome/brands/slack - link: https://bit.ly/publichopsworks + link: https://join.slack.com/t/public-hopsworks/shared_invite/zt-1uf21vitz-rhHKNdIf8GEiOf1EJ6Wzsw analytics: provider: google property: G-64FEEXPSDN @@ -290,11 +299,13 @@ extra_css: - css/custom.css - css/marctech.css - css/dropdown.css + - css/animation.css extra_javascript: - js/inject-api-links.js - js/dropdown.js - js/quickstart-fullscreen.js + - js/background-animation.js plugins: - search