From 030e4a546294a1a593a818443c91d21d59723351 Mon Sep 17 00:00:00 2001 From: MagicLex Date: Thu, 6 Feb 2025 11:47:28 +0200 Subject: [PATCH 01/24] Minor Update - On premise page content. --- .../on_prem/contact_hopsworks.md | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) 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 From 684c20af711d0f6542a933930580c6eaf807d7ee Mon Sep 17 00:00:00 2001 From: MagicLex Date: Fri, 28 Feb 2025 17:38:54 +0200 Subject: [PATCH 02/24] Significant Design Updates; Dark mode added. change of the css structure. --- docs/assets/images/hops-logo.png | Bin 6356 -> 5111 bytes docs/assets/images/hopsworks-logo.png | Bin 20421 -> 0 bytes docs/css/custom.css | 386 ++++++-- docs/css/dropdown.css | 50 +- docs/css/marctech.css | 1219 ++++++------------------- docs/index.md | 500 +++++----- docs/js/layout_improvement.js | 15 + mkdocs.yml | 19 +- 8 files changed, 867 insertions(+), 1322 deletions(-) delete mode 100644 docs/assets/images/hopsworks-logo.png create mode 100644 docs/js/layout_improvement.js diff --git a/docs/assets/images/hops-logo.png b/docs/assets/images/hops-logo.png index d3625ae07da68430e3bd5f46a1a7baf88dd474cc..20be7f6471f34a45882d761003c114dba85fbadb 100644 GIT binary patch literal 5111 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 literal 6356 zcmb`M*H;tH^Y;T%LX#x)4nb-Vq>3~l2BZ@ZFcd*UmEHtJlom=tl}-dC6e-e+5S1pO zgY-~Dsx+m86oHQq-@o9w`CZJ}b7tQ&XJ>A9=e1a*@qH$GZh8O!z@(>(FarQ6gsw~i zNOR?xGfoSmU+Q-MS^0Er4r8CEI?2Y}cRKtMqRkV4ZOBm{`1hf)DdwJ-od z$yg8oLH&OwTD^b$?(-r~yfgaC<;1~5bw#84)X>*IG3nG$Du--t^f*^_Q(n@RHD=Qk z;r4IVN9i!~(UFgIU_8nb5%6}Wr-B&)6osnPQ~iM1A4PM5Hxe14=3%>A*y8G`T^vY8XIGgU{= zlMnB86hh`|)w1-1PQ8K1x{x%^(Td}11ZuGUTgzn)`=`~t5e$6=KUiQY0&}$i9e?`Y z+EqZ&+SOqqY5cji&CPZ%{Ds)JjJ9c)6+wgsl!Pjs6XRpp~M;Ro==k+rp zO0GlwC503rU{TLXDe~pVic3x22$8hwm1-h=5$Vi|+B7KmW=(2vzQt8ArAGg?lHlJ> zT9_0EP{HR}W(2jZetWRldAKHK%+b62pY6F;Y1pfr4byKyjUX2Nw^-Yv35N9H;YMR0 z5=8$kq1Exxd3b5qg4<0G1ZK=djD0loe@QOP3KcQH)lRtKaqIClQ{{(^bYNM+MOLr2 zzPjnm+$5x?`>I)DW2Y9#1nnzf-#6WrmArHVHaJE#<8ChF=vQ@EX2BzQg!uJbU(;>g zV&_c8HW@rR3J9h*fT4Yr>sE~G>>YTx#n5cE{;h^MRwzQ8*8q&qEPpoz@!^LdWa#+P zw0z+h;F*hLN0)y^>il$tEc?)I)E9C6*xtmmLbj=m4{+eI<(L3kHeuCtuKxF6BF~p^ z7J8kdHJFQ<5ASI-_CPybD zYIDXbU0GncY*K=g6!O$q7uAVP&YK8sXzg|Jdm0^dkoWNV0?XHZp%SC&*yP0T2ya6H zOH+r~QN{srSRK8&Fnm3=9FToFyM=w5ApoN@7h?|JJnYp9+eU>M zeL9`GeIdk#lRhXv+z#Nr;kN+vtf>n(5C>`rE;zpZZ7#rvY-}s#& z1RvHTfJSdKLv?tD+e*x3hu=8tk3a%a4WOSsUJkxHF<5;AG)qjvvU`xsu*2S@*i9O*phhG=!7)CH z`5ocLMxai})N(Du8{F`rUCKGe}1Pfub?(-_^2;?~}vx$VKq4em#mTCO6R zqTN^sTwc?z3X>mE@E4#-?s7fMtnI^s8`1AiZ)IDvD(jiMmx_X|k!;&k3933^SB++V zx)7zt3A$%viGY=}rNN+l7pc1i6HJq6IuTQ5QvjaggcNxotZ!n)1Xbv|>7#S>%X+V0 zO^3Id23#O2eqAG`I9x!QS3&B7#3PI|N^4XTb8w^C!15FDO$zOZFV|lRvpV3AUf(qo zc!FEf3X}4qo+?>cYXx468%f*olsUDQV0yZ*Na^PA@x+vT;9{quS1AHP$H)dsz2M%$e)}lZ!e+#KcsErt~ z3i-qZe(nbB7hcdoY;NjdM2l8)>w-EoWW)1=zkGHS!GbK4RV|^vPKrZ>YG}Y_VZa0z z@5_)325%3>SbTxpo;1AJ&@!j*6S~Gl1im8&c(fh7@Kreo|DLTF1ut6N_I-NEJ9huC z@gjTmA9yVCM}>AsNP=322<#eSgUxw@#>)35N2Up3q=GggU|+?)lnRW_|CIP@YyD9^ zy{i;KZjU=hS_>nNQ)QMvX3^)Z!7N(ng9*cQA&F^Rzh1+WK6gPRuT`gy7gN3WCUv32 z_N>g%FpJ?TIs3}7gu(?zyW$3>icX^g1Il+IN>k8pRkj7#rN3^04@_a^G~OY^sba;N zouZZVR6iS6y}3S>h2qXQ=TO6c$x=U~qC8P z|IFe399BpEs{#ux!+laxnmidTM?Zgk*ByCk$mc@u0(I_*NWrJwgi?u>Jz+XZol_8? zXDRI1_PeQ38NYjai2#>&E8NE{-cXDkX?LJNH>CSvZu8@fcslY4 zxj9K2Vpy)?dB>T!$wOnbthBt{wOrDuvDIBs?{qG?i19tBB5tHz2dz`-IKBgc6jcI$ z(w>F*C$V?I=g$idcAw_On>TjGUGx&p;$Ax777=qPPunk@Y>1{Y4`ZQiWu(_0Cx6^U zWp>)et25eY>1n~i-^RlyW$!$HChRq*W1E`rg?}|DYOD4aBBYyMDg&fU0S?Z+XUe@1 zADn%xTNCJV(ej9rV%Bn5ubMh{SR00BW|tN)2S6Q%*V;YxpNWUSeBVXI5DoAz5J|Bh z-omx^fKA3%0X*2AQ_hR`zJ1ekZ*I>^y+D*2Mtk68_PIu4N21MNk)OxeWQfBJWG}s6 zB^4Vojvt(PI__QAHc)%`M=x{=iC~fLYL^QJfMXkK^aNk?BO#K@;@7X-cwHm*cKb9a zoQ2q)R2i<+Ra#WZE03)YVOR`oIliOdL4pQ5uwuz7fyKdicr<szdL=6dU?r{0=)xO$UKd?X;Wye(irh6$E*LHn)wUn#)l6I zMPcUD=dy$4#}3q$178h5AcFARbIz4dDz5KhJ3uSG7UrB0!xS+aK{8*g@55UZ-P#*0 zwwtnZoBTJ^nFb{N*a%3mmp3_UqYe+)-T_nKsCY7sMZ|WgjO31r5G9K9CDCh16CfHKGo-NU~L77Yz zo6?%gH$_=QzkF8j4IHf#dRvC`bKg*p7YnRUBphWFd`fA)ZpM z0vqSQ_795?-V^93JTKQ-dg|{NyXc?L|t~Y0WRHANS%l1V>`~qf?rmx&HKOkeq z=SFtQ*qQ8(U{7xnvF&#kSNhS~ z*>>qwf3*8U(r5_MU+HRMlOMz8INaH5_#Cfj7vk& zD_sl->rMOvgt?+JFF%v==T((yxn<`Z)kvOvU#X4zApNqb`CL!J*&Of7u*WND&i3E? z+Vh;rvs?V3`-U`zAqOYYFo+DZ?4LN`rKm$c%_i&<(Hmpv3eQ9`GFi%r9y;Ol35v4e zYuP)xqrcWMrrpN0ha9&C+Q}Q{0ike-W{0FVVrw%6bkjpOL@CxCzNZTupxnju*A$MV zrsGSeGe*=NPy{3Ac^hvB%-(7O<&(d{`Odi%e>yTz!#EQp;GW%ztoSuj#-AQHekmSJ zMFwWu8f2n$pM(-?1;y?6z}1{8a*kkyAYaR>>|1TnIYS)E{yG_HA1N~7%v(B1HWq}d zWUzaoIHsB8YipxhPye9`fhy5AGJvbfgReCGBUFxE%1{Zt(OsYNJSqukF?nn<@JDOz zrV7sGO-qYWXa_zSh_07wCE?N6{gGB0aDR)Pjxb!&n5|(oPTLfnsTQkotqtHCoVR#@k?d5x2|A<)H+#WJiBL&A3*qg4M?yG--NK>}Z1>@Oj ztSG^LNk;LvR=3KJb>@4IzOu%et%1xieoYa<450$X^>w`@lDPiF-aJ(34Ltd;H2HK6 z8NO-R?Y|Z;DxQ0;(1LV5nOaYou9<0tsOs{m395toA(8|)lz+XeOgp!gRRfKbJl%0y zBcoYQd68WgB>(E#42P|;ZyTw|T2igHe_ejUI&d>?^5B3&2vM3wrcMApq08;=rtkM$ z{u1yh4@ zy9QSIMurMoj^T?826#euo&c=nERm5wEzO1uP3!gAoH;zH^byS^-|=4hIJ~0_3W? zYG9vz`9XWkSu85aVfmg?`mcE{%v>bwm^VXPW1U>^-oqnAypP`)0SxKP`?&I@aS-{# z+RL}a^7t-|@Ue8TxWIO7EIvbf=cdNn-4B%lbzB4<#w&3ln82N>J&$ty(6CR?t|-H< zhXKRAr^f^F3V*1bhq%KD@y=Gs4Hh}9g^h(D3Zb@%9AbjErcxI)V>l4m+*77XtiM9XX* zIm1K1483b~@oYyqAFP)hh0yR5v}o%a9#spiU#pvk#$GtbXbq8XmO8od60ySKuW}?4 z2a+g4r;NR}2)EoNtF1`2Oq~sFFJstEjCQ6Qi^6-l|J7g;A82PAls-DDmW>@Foo+gm z&kL%Ubel{`Iho(9G~R9k2j(u{dr4jv_Q&I>}DFjr}+`1ZyH}a_-GPf7``Uv8&Il79(i1 zb0d0v99Pt{cV`l%#RUBs<$)vFJ;IuN)30-wGD&Kisdk3*AMfAIS%`_*o31@sdqMc{=Ff;MfoAgu zQNZlUB~ca!!$>ZM(Qa)T180|5LwacoG0HjcZ`0a}7eGO1z-tCC)B^e^|rXH_3aW}WN2IOdHSuKz4~%dkk8L_gug?Rf#-H(`iwyiv6V zMRQVeeAZQ^6*5;7boL=Bw^$S&7r8ckLVMRizEZ7T;f+7$G=3d#WwD@lHNY^^H#)Q7 zkg$c9JAERRwK`8NY}~sg%(w&E_7qw>Mf?YZe%_Hw-I~|=sCina27C5$b@c30P?a3fp2?I)eB)ee=Q&d}eGdQk<6 zixh1jMQ{`=qLgG9u5=lkikfO+5XGrvnXTLaj&P9zd-VOgxal+lag4fU@)?T$DF$=x zI6$u6mI?v#;KxZnt4Eo(`>etxdBuf}iLyxWBQRZgN9zG@f!((G*ir%^VqS0pNxmP( zN@67>cecVuVcM>FTIr{p3e4Ga=cU2H4BN31@J1UgBkJ)Zj|_{oUTgkxR;YCtkf<#T z$6M(T3-0u&mLY}{RL}An&?v|Q%yoCPzUHAqH34hN!_hw^a&9Oy{Tz)$KDBJOej!U9 z)2lqoBgT$^!m5I$KETjeB(^F`lpl#k{wJc~TbAU zAyED;5`-}Je&Z=+dLt2iO+F6rtkfTg0 z{63Ho%9>|=lc0mpRrMWp`7x49D$gkTu@Vj>QW$Kgc~lUhn)RzTnD(<-POv77V98O) zqC~L9Y!T_(Xaj}(TIA^s1S7b72I5M;AnAKuiEZ>mSY>NUZnLIqTc2f47TEVEc5vKQ zmNL+XIFDT&D(b}OJ!Miz8|v)c8aE!hC}9^?i=D)5I8s4>(un@bb>0@QI=oSpPLvA) z@oz^^=wdiMdCqZ5)lrWCTaQAyw&{!fvvlLveeT?F)MYe?jeE}@Y*Hvwqs9Q$dHjjQ zP)dGX^MH{O^SE8FH!)m>9SF*~c2!}DQbH>gkM5EO8k;;IcQGg4V#Yy1$#&Iu1^Jd^ z$vp}x;KX7gQEQy}VSxzgdSDHWfw)>R7Nk1;g!M|)U@c^XYrO%sPK}PKCAodS;+OBz zkNiwS=nLB+ev!^P#&li-92tNJSS%e;>w8YNdnHna>(+JvB8;O0!rh}^2eAgY4e;iY(wo$P z@gvrpIKc1fSu}iTY)|59sA42DQ&QPs8{=LN|5GwL+%HRm*>9Wo{PCB4}cBn2Y3WsG=7_G`viM$s%;=adr zu;-6fzy-SO)bBFSVV7uLLTa&_Zd+}gO|fmEk73LA$P5L^b->AXJ1QCBSHtN*=H+Xq zgg6apS*pcv;xd|Hf+{GuFWqX2XK}+~UYL9l4U|>DUV4U%qSD3lrBH)$!xxXU7dS1U zYDqxmpOnxv8YS{bfA6098|xTbEzDScIt0_la9BQMROrDMRiODl6koJK@qf+Z|9@nk e-)Q{e?z``UxWtE+SHBbhfS$H7q6+>v;{O44aExI9 diff --git a/docs/assets/images/hopsworks-logo.png b/docs/assets/images/hopsworks-logo.png deleted file mode 100644 index 36f20bb120bbfac7ec822a7a5094469f75754db4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20421 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

Y_~oqMbws!kC_?Unj15B5h?RgtGa)YCk&i`u|ZE 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 LcDwqP+mrtQXA#fc diff --git a/docs/css/custom.css b/docs/css/custom.css index 18236a29f..747931583 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -1,129 +1,341 @@ -[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); + +/* 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); +} + +.md-header__button { + color: var(--md-hopsworks-text); +} + +.md-header__button:hover { + color: var(--md-hopsworks-primary); } -.md-tabs__item { - min-width: 2.5rem; +.md-header__topic .md-ellipsis { + font-weight: 500; } -.md-tabs__item:hover { - background-color: var(--md-tertiary-fg-color); - transition: background-color 450ms; +/* 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); +} + +/* Navigation tabs */ +.md-tabs { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); + border-bottom: 1px solid var(--md-hopsworks-border); +} + +.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; +} + +/* Sidebar styling */ +.md-nav { + font-size: 0.8rem; +} + +.md-nav__title { + color: var(--md-hopsworks-text); + font-weight: 600; + font-size: 0.85rem; +} + +.md-nav__link { + color: var(--md-hopsworks-text); + margin: 0.3rem 0; +} + +.md-nav__link:hover, +.md-nav__link:focus, +.md-nav__link--active { + color: var(--md-hopsworks-primary); +} + +.md-sidebar { + background-color: var(--md-hopsworks-background); } .md-sidebar__scrollwrap { - background-color: var(--md-quaternary-fg-color); - padding: 15px 5px 5px 5px; - border-radius: var(--border-radius-variable); + background-color: var(--md-hopsworks-card-bg); + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); + margin: 1rem; } -.image_logo_02 { - width: 450px; +/* Typography adjustments */ +.md-typeset { + font-size: 0.8rem; + line-height: 1.6; + color: var(--md-hopsworks-text); } -/* End of Lex did stuff here */ +.md-typeset h1 { + color: var(--md-hopsworks-text); + font-weight: 600; + font-size: 1.8rem; + margin-top: 1.5rem; + margin-bottom: 1rem; +} -/* no-icon style for admonitions */ -.md-typeset .no-icon > .admonition-title::before, -.md-typeset .no-icon > summary::before { - display: none; +.md-typeset h2 { + color: var(--md-hopsworks-text); + font-weight: 600; + font-size: 1.4rem; + margin-top: 1.5rem; + margin-bottom: 0.8rem; } -.md-typeset .no-icon > :is(.admonition-title, summary) { - padding-left: 1rem; + +.md-typeset h3 { + color: var(--md-hopsworks-text); + font-weight: 500; + font-size: 1.2rem; } -/* end of no-icon style */ -.md-header__button.md-logo { - margin: 0.1rem; - padding: 0.1rem; +.md-typeset h4 { + color: var(--md-hopsworks-text); + font-weight: 500; + font-size: 1rem; } -.md-header__button.md-logo img, -.md-header__button.md-logo svg { - display: block; - width: 1.8rem; - height: 1.8rem; - fill: rgba(43, 155, 70, 0.1); +/* Link styling */ +.md-typeset a { + color: var(--md-hopsworks-primary); + text-decoration: none; } -.md-tabs { - width: 100%; - overflow: auto; - color: var(--md-primary-bg-color); - background-color: var(--md-secondary-fg-color); - transition: background-color 250ms; +.md-typeset a:hover { + text-decoration: underline; +} + +/* Code styling */ +.md-typeset code { + background-color: var(--md-hopsworks-inline-code-bg); + border-radius: var(--md-hopsworks-radius); + padding: 0.2em 0.4em; + font-size: 85%; +} + +.md-typeset pre > code { + background-color: transparent; + padding: 0; +} + +.md-typeset pre { + background-color: var(--md-hopsworks-code-bg); + border: 1px solid var(--md-hopsworks-border); + border-radius: var(--md-hopsworks-radius); +} + +/* 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; +} + +.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); } -.wrapper { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 10px; - grid-auto-rows: minmax(100px, auto); +.md-button--primary:hover { + background-color: var(--md-hopsworks-secondary); + border-color: var(--md-hopsworks-secondary); + color: var(--md-hopsworks-card-bg); } -.wrapper * { - border: 2px solid green; - text-align: center; - padding: 70px 0; +/* Footer styling */ +.md-footer { + background-color: var(--md-hopsworks-card-bg); + color: var(--md-hopsworks-text); + border-top: 1px solid var(--md-hopsworks-border); } -.one { - grid-column: 1 / 2; - grid-row: 1; +.md-footer-meta { + background-color: var(--md-hopsworks-background); } -.two { - grid-column: 2 / 3; - grid-row: 1; + +/* 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); } -.three { - grid-column: 3 / 4; - grid-row: 1; + +.md-typeset .admonition-title { + font-weight: 600; } -.four { - grid-column: 4 / 5; - grid-row: 1; + +/* 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); } -.five { - grid-column: 1 / 3; - grid-row: 2; + +[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); } -.six { - grid-column: 3 / 5; - grid-row: 2; + +/* Light/dark toggle */ +.md-header__button.md-icon { + color: var(--md-hopsworks-text); } -/* Jupyter Stuff */ -.jupyter-wrapper .jp-CodeCell .jp-Cell-inputWrapper .jp-InputPrompt { - display: none !important; +.md-header__button.md-icon:hover { + color: var(--md-hopsworks-primary); } -@media screen and (max-width: 479px) { - .md-sidebar--primary, - .md-sidebar { - z-index: 50 !important; - } - .md-logo { - visibility: hidden; - } +.image_logo_02 { + width: 400px; + height: 200px; + margin: 0 auto; + display: block; } + +/* Styling overrides for Hopsworks documentation */ +.md-grid { + max-width: 1200px; /* Wider content area */ +} \ No newline at end of file diff --git a/docs/css/dropdown.css b/docs/css/dropdown.css index c1c768fa2..96548c876 100644 --- a/docs/css/dropdown.css +++ b/docs/css/dropdown.css @@ -1,55 +1,53 @@ -/* Style The Dropdown Button */ +/* Dropdown Button */ .dropbtn { - color: white; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: transparent; + color: var(--md-hopsworks-text); + padding: 0; + font-size: 0.8rem; border: none; cursor: pointer; + font-weight: 400; } -.md-tabs__list { - contain: inherit; -} -.md-tabs { -overflow: inherit; -} -.md-header { - z-index: 1000 !important; +/* Dropdown button on hover & focus */ +.dropbtn:hover, .dropbtn:focus { + color: var(--md-hopsworks-primary); } -/* The container

- needed to position the dropdown content */ +/* The dropdown container */ .dropdown { - position: absolute; + position: relative; display: inline-block; } /* Dropdown Content (Hidden by Default) */ .dropdown-content { - display:none; - font-size: 13px; + display: none; position: absolute; - background-color: #f9f9f9; + background-color: var(--md-hopsworks-card-bg); min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 1000; - border-radius: 2px; - left:-15px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.1); + border: 1px solid var(--md-hopsworks-border); + z-index: 1; } /* Links inside the dropdown */ .dropdown-content a { - color: black; + color: var(--md-hopsworks-text); padding: 12px 16px; text-decoration: none; display: block; + font-size: 0.8rem; } /* Change color of dropdown links on hover */ -.dropdown-content a:hover {background-color: #f1f1f1} +.dropdown-content a:hover { + background-color: var(--md-hopsworks-background); + color: var(--md-hopsworks-primary); +} /* Show the dropdown menu on hover */ .dropdown:hover .dropdown-content { display: block; -} - -/* Change the background color of the dropdown button when the dropdown content is shown */ -.dropdown:hover .dropbtn { -} +} \ No newline at end of file diff --git a/docs/css/marctech.css b/docs/css/marctech.css index 78fddc27e..50bb09724 100644 --- a/docs/css/marctech.css +++ b/docs/css/marctech.css @@ -1,1073 +1,378 @@ +/* Simplified Hopsworks Architecture Diagram Styles */ :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; + --primary-color: #1eb382; + --secondary-color: #188a64; + --primary-light: #e6fdf6; + --text-color: #333333; + --text-light: #666666; + --border-color: #e5e5e5; + --bg-color: #f5f5f5; + --card-bg: #ffffff; + --hover-color: #f0f0f0; + --shadow: 0 0px 0px; + --radius: 0.8rem; +} + +/* Dark mode variables */ +[data-md-color-scheme="slate"] { + --primary-color: #2be9ac; + --secondary-color: #23bd8e; + --primary-light: #1a372e; + --text-color: #e0e0e0; + --text-light: #b0b0b0; + --border-color: #444444; + --bg-color: #252525; + --card-bg: #323232; + --hover-color: #404040; + --shadow: 0 0px 0px rgba(0, 0, 0, 0); +} + +/* Main container */ +.hopsworks-diagram { + max-width: 1000px; + margin: 0 auto; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + color: var(--text-color); + background-color: var(--bg-color); + padding: 20px; + box-sizing: border-box; +} + +/* Header styles */ +.platform-header { + text-align: center; + margin-bottom: 30px; } -.marctech_main a:visited{ - color: var(--md-tertiary-fg-color); - border-bottom: 1px dotted var(--md-tertiary-fg-color) !important; - +.platform-logo { + max-width: 180px; + margin-bottom: 10px; } -.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; +.platform-title { + font-size: 1.5rem; + font-weight: 500; + margin: 0; + color: var(--primary-color); } -.image_logo{ - width: 69%; - background-color: rgba(255, 255, 255, 0.521); - z-index: 50; - padding: 0px 15px 0px 15px; - margin-bottom: 10px; +.platform-subtitle { + font-size: 0.9rem; + font-weight: 400; + margin: 5px 0 0; + color: var(--text-light); } -.layer_02{ - pointer-events: none; +/* Layout rows */ +.architecture-row, .platform-row { + display: flex; + gap: 20px; + margin-bottom: 20px; } -.round-frame{ - pointer-events: initial; +/* Section styling */ +.feature-store-section, .mlops-section, .tech-section, .deployment-section { + flex: 1; + background-color: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius); + box-shadow: var(--shadow); + padding: 20px; } -.marctech_main { - margin-top:-20px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* Section headers */ +.section-header { 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; + gap: 10px; + margin-bottom: 15px; + padding-bottom: 10px; + border-bottom: 1px solid var(--border-color); } -.collumns { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - height: 100%; - -webkit-box-align: stretch; - -webkit-align-items: stretch; - -ms-flex-align: stretch; - align-items: stretch; +.section-icon { + width: 20px; + height: 20px; + stroke: var(--primary-color); + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + fill: none; } -.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; +.section-title { + font-size: 1.1rem; + font-weight: 500; + margin: 0; } -.enterprisefs { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* API sections */ +.api-container { 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; + gap: 20px; + margin-bottom: 20px; } -.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; +.api-column { 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; + gap: 10px; } -.rec_frame:hover { - border-color: #c2c2c2; - box-shadow: none; -} - -.name_item { - font-size: 0.7rem; - line-height: 120%; - font-weight: 700; -} - -.name_item.db { - position: relative; - z-index: 3; - text-align: left; +.api-label { + font-size: 0.8rem; + color: var(--text-light); + margin-bottom: 5px; + font-style: italic; } -.name_item.small { - font-size: 0.6rem; +.api-link { + display: block; + background-color: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius); + padding: 10px; + color: var(--primary-color); + text-decoration: none; font-weight: 500; -} - -.name_item.ingrey { - padding-bottom: 20px; -} - -.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; + font-size: 0.9rem; + transition: all 0.2s ease; 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; - text-align: center; +.api-link:hover { + border-color: var(--primary-color); + background-color: var(--primary-light); } -.icondb { - position: relative; - width: 25px; - min-width: 25px; - margin-right: 10px; +.api-link.sub { + margin-left: 15px; + border-style: dashed; } -.db_frame { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* Feature tools */ +.feature-tools { 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; + justify-content: space-between; + gap: 10px; } -.arrowdown { - position: relative; - z-index: 0; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.feature-tool { + flex: 1; display: flex; - margin-top: -10px; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; + align-items: center; justify-content: center; + gap: 8px; + background-color: var(--primary-light); + border: 1px solid var(--primary-color); + border-radius: var(--radius); + padding: 8px; + color: var(--text-color); + text-decoration: none; + font-size: 0.8rem; + font-weight: 500; + transition: all 0.2s ease; } -.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; +.feature-tool:hover { + background-color: var(--hover-color); + box-shadow: var(--shadow); } -.MT_heading3.green { - color: #1eb182 !important; +.feature-tool-icon { + width: 16px; + height: 16px; + stroke: var(--primary-color); + stroke-width: 2; + fill: none; } -.column_sides { - position: relative; - z-index: 2; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* MLOps workflow */ +.mlops-workflow { 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; + justify-content: space-between; + margin-bottom: 20px; } -.center-content { - z-index: -50; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.mlops-step { display: flex; - width: 750px; - height: 670px; - 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: center; - -ms-flex-line-pack: center; - align-content: center; - border-radius: 10px; - background-color: transparent; -} - -.image { - width: 260px; -} - -.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; + gap: 5px; + text-decoration: none; + color: var(--text-color); + transition: all 0.2s ease; } -.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; - 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; +.mlops-step:hover { + color: var(--primary-color); } -.rec_frame_main.no_content:hover { - border-color: #1eb182; - box-shadow: 4px 4px 0 0 rgba(88, 88, 88, 0.16); +.mlops-step-icon { + width: 30px; + height: 30px; + stroke: var(--primary-color); + stroke-width: 2; + fill: none; } -.name_item_02 { +.mlops-step-label { 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; - 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; + font-weight: 500; } -.rec_frame_main-white.dotted { - border-style: dotted; +.workflow-arrow { + width: 24px; + height: 24px; + stroke: var(--text-light); + stroke-width: 2; + fill: none; } -.column { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* MLOps features */ +.mlops-features { 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; -} - -.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; -} - -.logo-holder { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; + gap: 10px; } -.infra { - text-align: center; - position: relative; - z-index: 30; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.mlops-feature { + flex: 1; 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; + gap: 5px; + padding: 10px; + background-color: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius); + text-decoration: none; + color: var(--text-color); + transition: all 0.2s ease; } -.infra:hover { - border-style: solid; - border-color: #585858; +.mlops-feature:hover { + border-color: var(--primary-color); + background-color: var(--primary-light); } -.text_and_icon { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - 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; +.mlops-feature-icon { + width: 20px; + height: 20px; + stroke: var(--primary-color); + stroke-width: 2; + fill: none; } -.svg_icon { - width: 33px; - margin-right: 10px; - margin-left: 10px; +/* Tech grid */ +.tech-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10px; + margin-bottom: 15px; } -.layer_02 { - position: absolute; - z-index: 10; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +.tech-item { 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; -} - -.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; -} - -.round-frame:hover { - border-color: #c2c2c2; - box-shadow: none; -} - -.round-frame.top-left { - left: 4%; - top: 15%; - right: auto; - bottom: auto; -} - -.round-frame.bottom-left { - left: 4%; - bottom: 15%; -} - -.round-frame.top-right { - left: auto; - top: 15%; - right: 4%; - bottom: auto; -} - -.round-frame.bottom-right { - left: auto; - top: auto; - right: 4%; - bottom: 15%; + gap: 5px; padding: 10px; + background-color: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius); + text-decoration: none; + color: var(--text-color); + font-size: 0.8rem; + transition: all 0.2s ease; } -.side-holder { - z-index: -1; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - 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; +.tech-item:hover { + border-color: var(--primary-color); + background-color: var(--primary-light); } -.infra-icon { - width: 25px; - height: 25px; +.tech-icon { + font-size: 1.2rem; } -.div-block { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; +/* Cloud providers */ +.cloud-providers { 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; + gap: 10px; } -#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; -} - -#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; +.cloud-provider { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 15px 10px; + background-color: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius); + text-decoration: none; + color: var(--text-color); + font-size: 0.8rem; + transition: all 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; +.cloud-provider:hover { + border-color: var(--primary-color); + background-color: var(--primary-light); } -#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; +.cloud-icon { + width: 24px; + height: 24px; } - -/* - - -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; -} -@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; +/* Responsive layout */ +@media (max-width: 768px) { + .architecture-row, .platform-row { + flex-direction: column; } - .w-col { - width: 100%; - left: auto; - right: auto; + + .api-container { + flex-direction: column; } - .w-col-small-1 { - width: 8.33333333%; + + .tech-grid { + grid-template-columns: repeat(2, 1fr); } - .w-col-small-2 { - width: 16.66666667%; + + .mlops-workflow { + flex-direction: column; + gap: 20px; } - .w-col-small-3 { - width: 25%; + + .workflow-arrow { + transform: rotate(90deg); } - .w-col-small-4 { - width: 33.33333333%; + + .cloud-providers { + flex-wrap: wrap; } - .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%; + + .cloud-provider { + min-width: calc(50% - 10px); } } -@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; - } - .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%; +@media (max-width: 480px) { + .feature-tools, .mlops-features { + flex-direction: column; } - .w-col-tiny-11 { - width: 91.66666667%; + + .tech-grid { + grid-template-columns: 1fr; } - .w-col-tiny-12 { - width: 100%; + + .cloud-provider { + min-width: 100%; } } \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 2d72b7ab1..b70437968 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,273 +11,275 @@ hide: } -
-
-
-
-
-
-

Enterprise Data

-

Feature Engineering

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

Feature Store & MLOps Platform

+

Store, discover, and serve ML features and models

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

Feature Store

-
-
-
-
-
-

Enterprise Feature Store

-
-
-
+ +
+ -
-
-
-
Govern & Monitor
-
-
-
Serve
-
-
-
Share
& Re-use
-
-
-
Create
-
-
- -
-
-
-
- -
-
-
-
- Write API - - -
-
-
-
-
- Read API - -
-
-
- - -
- + +
-
-
-
-
-
-

Enterprise AI

-

MLOps

-
-
-
-
-
- -
- -
-
-
- -
-
- - -
-
+ + +
+ + + +
+ + +
-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. +# Hopsworks: Feature Store & MLOps Platform + +Hopsworks is a modular data platform with a Python-centric Feature Store and comprehensive MLOps capabilities. Use it as a standalone Feature Store or leverage its full suite of tools to manage your entire ML lifecycle. -## 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. +## Feature Store -## 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. +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 in any Python, Spark, or Flink environment, either inside or outside Hopsworks. + +Use the Python frameworks you already know to build production feature pipelines: +- Compute aggregations in Pandas +- Validate feature data with Great Expectations +- Reduce dimensionality with embeddings and PCA +- Test feature logic end-to-end with PyTest +- Transform features with Scikit-Learn, TensorFlow, and PyTorch + +## Wide Range of Capabilities + +- **Feature Pipelines**: Support for Python, PySpark, Spark, Flink, and SQL +- **Storage Flexibility**: Store offline features in Hopsworks as Hudi tables or connect to external systems (Snowflake, Databricks, Redshift, BigQuery) +- **Online Serving**: Industry-leading throughput and availability with RonDB ## 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. +Hopsworks provides comprehensive model management through KServe: +- Feature/prediction logging to Kafka +- Secure, low-latency model deployments via Istio +- Model versioning with the Model Registry +- Vector database for similarity search through OpenSearch -## 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. +## Project-based Collaboration -## 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. +Hopsworks creates secure sandboxes for teams to collaborate and share ML assets: +- Fine-grained sharing across project boundaries +- End-to-end team responsibility from raw data to models +- Development, staging, and production environments +- Versioning, lineage, and provenance for all ML assets -## 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 ) +## Available on Any Platform -## 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. +Deploy Hopsworks anywhere: +- Cloud: AWS, Azure, GCP +- On-Premises: Ubuntu/Redhat compatible, including air-gapped environments +- Serverless: Fully managed platform for features and models -## 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. +## Join the Community -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. +- Get help in the [Hopsworks Community](https://community.hopsworks.ai/) +- Follow us on [Twitter](https://twitter.com/hopsworks) +- Check out our [product releases](https://github.com/logicalclocks/hopsworks/releases) +- Join our [Slack channel](https://join.slack.com/t/public-hopsworks/shared_invite/zt-24fc3hhyq-VBEiN8UZlKsDrrLvtU4NaA) \ No newline at end of file diff --git a/docs/js/layout_improvement.js b/docs/js/layout_improvement.js new file mode 100644 index 000000000..be218338d --- /dev/null +++ b/docs/js/layout_improvement.js @@ -0,0 +1,15 @@ +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'); + } + } + }); + } +}); diff --git a/mkdocs.yml b/mkdocs.yml index d8cdaf8a2..fff24fc19 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -257,14 +257,27 @@ theme: 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 - + extra: hopsworks_version: dev version: From c1a8377ceb371128b72ac83aa9582486fdca9073 Mon Sep 17 00:00:00 2001 From: MagicLex Date: Tue, 4 Mar 2025 09:58:56 +0200 Subject: [PATCH 03/24] Improve site styling, add modern architecture diagram, and attempt API dropdown fixes - Redesigned index page with modern architecture diagram - Reduced top margins across the site for better content visibility - Created consistent width for content pages - Added full_width page support - Created CLAUDE.md with build instructions - Attempted fixes for API dropdown menu z-index issues - Fixed white magnifying glass icon in light theme search bar --- CLAUDE.md | 22 ++ docs/css/custom.css | 256 ++++++++++++++++++++- docs/css/dropdown.css | 7 +- docs/index.md | 412 +++++++++++++--------------------- docs/js/inject-api-links.js | 14 ++ docs/js/layout_improvement.js | 6 + docs/overrides/main.html | 11 + 7 files changed, 474 insertions(+), 254 deletions(-) create mode 100644 CLAUDE.md 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/docs/css/custom.css b/docs/css/custom.css index 747931583..7cadad8e6 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -43,6 +43,14 @@ background-color: var(--md-hopsworks-background); } +.md-content__inner { + padding-top: 0.5rem; +} + +.md-content__inner > :first-child { + margin-top: 0; +} + /* Header styling to match Hopsworks app */ .md-header { background-color: var(--md-hopsworks-card-bg); @@ -57,6 +65,7 @@ .md-header__title { color: var(--md-hopsworks-text); + margin-left:0rem !important; } .md-header__button { @@ -90,11 +99,17 @@ 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; +} + /* Navigation tabs */ .md-tabs { background-color: var(--md-hopsworks-card-bg); color: var(--md-hopsworks-text); - border-bottom: 1px solid var(--md-hopsworks-border); + border-top: 1px solid color-mix(in srgb, var(--md-hopsworks-border) 30%, transparent); } .md-tabs__link { @@ -153,7 +168,7 @@ color: var(--md-hopsworks-text); font-weight: 600; font-size: 1.8rem; - margin-top: 1.5rem; + margin-top: 0.5rem; margin-bottom: 1rem; } @@ -161,7 +176,7 @@ color: var(--md-hopsworks-text); font-weight: 600; font-size: 1.4rem; - margin-top: 1.5rem; + margin-top: 1rem; margin-bottom: 0.8rem; } @@ -169,12 +184,14 @@ 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 */ @@ -233,6 +250,7 @@ border-radius: var(--md-hopsworks-radius); box-shadow: var(--md-hopsworks-shadow); transition: all 0.2s ease; + margin-top: 0.5rem; } .docs-card:hover { @@ -338,4 +356,236 @@ /* Styling overrides for Hopsworks documentation */ .md-grid { max-width: 1200px; /* Wider content area */ +} + +/* Make sure index and content pages have consistent widths */ +.md-content__inner { + max-width: 1000px; + margin: 0 auto; + position: relative; + z-index: 1; /* Lower z-index for content */ +} + +/* Modern Architecture Diagram */ +.platform-architecture { + max-width: 1000px; + margin: 20px auto 40px; + position: relative; + display: flex; + flex-direction: column; + gap: 15px; +} + +/* For full width pages */ +.md-content__inner.full-width { + max-width: none; + z-index: 1; /* Keep z-index low */ +} + +.architecture-header { + text-align: left; + margin-bottom: 15px; +} + +.arch-title { + font-size: 1.5rem; + font-weight: 500; + margin-bottom: 5px; + color: var(--md-hopsworks-text); +} + +.arch-subtitle { + font-size: 0.95rem; + color: var(--md-hopsworks-text-light); + margin: 0; +} + +.architecture-tiers { + display: flex; + gap: 15px; + height: 300px; +} + +.architecture-tier { + flex: 1; + display: flex; + flex-direction: column; + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); +} + +.tier-header { + padding: 15px; + border-bottom: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-background); +} + +.tier-title { + font-size: 1.1rem; + font-weight: 500; + margin: 0; + color: var(--md-hopsworks-text); +} + +.tier-description { + font-size: 0.85rem; + margin: 5px 0 0 0; + color: var(--md-hopsworks-text-light); +} + +.tier-components { + flex: 1; + display: flex; + flex-direction: column; + padding: 15px; + gap: 10px; + overflow-y: auto; +} + +.tier-component { + padding: 10px; + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-background); +} + +.component-title { + font-size: 0.9rem; + font-weight: 500; + margin: 0 0 5px 0; + color: var(--md-hopsworks-text); +} + +.component-description { + font-size: 0.8rem; + margin: 0; + color: var(--md-hopsworks-text-light); +} + +/* Interlude Text */ +.interlude-text { + max-width: 1000px; + margin: 30px auto 40px; + text-align: left; +} + +.interlude-title { + font-size: 1.4rem; + font-weight: 500; + margin-bottom: 10px; + color: var(--md-hopsworks-text); +} + +.interlude-description { + font-size: 0.95rem; + color: var(--md-hopsworks-text-light); + line-height: 1.5; +} + +/* Feature Navigation Grid */ +.feature-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + margin: 30px auto; + max-width: 1000px; +} + +.feature-card { + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); + padding: 25px; + transition: all 0.2s ease; +} + +.feature-card:hover { + border-color: var(--md-hopsworks-primary); +} + +.feature-title { + font-size: 1.1rem; + font-weight: 500; + margin-bottom: 10px; + color: var(--md-hopsworks-text); +} + +.feature-description { + font-size: 0.85rem; + color: var(--md-hopsworks-text-light); + margin-bottom: 15px; +} + +.feature-links { + margin-top: 10px; +} + +.feature-link { + display: block; + font-size: 0.8rem; + color: var(--md-hopsworks-primary); + margin-bottom: 5px; + text-decoration: none; +} + +.feature-link:hover { + text-decoration: underline; +} + +/* Deployment Options */ +.deployment-options { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 15px; + margin: 30px auto; + max-width: 1000px; +} + +.deployment-option { + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-card-bg); + padding: 20px; + text-align: center; + transition: all 0.2s ease; +} + +.deployment-option:hover { + border-color: var(--md-hopsworks-primary); +} + +.placeholder-icon { + width: 40px; + height: 40px; + background-color: var(--md-hopsworks-background); + margin: 0 auto 10px; +} + +.deployment-title { + font-size: 0.9rem; + font-weight: 500; + color: var(--md-hopsworks-text); +} + +/* Inner MLOps Components Grid */ +.mlops-components { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 15px; + margin-top: 15px; +} + +.mlops-component { + border: 1px solid var(--md-hopsworks-border); + background-color: var(--md-hopsworks-background); + padding: 15px; +} + +.component-title { + font-size: 0.9rem; + font-weight: 500; + margin-bottom: 5px; + color: var(--md-hopsworks-text); +} + +.component-description { + font-size: 0.8rem; + color: var(--md-hopsworks-text-light); } \ No newline at end of file diff --git a/docs/css/dropdown.css b/docs/css/dropdown.css index 96548c876..8b576801e 100644 --- a/docs/css/dropdown.css +++ b/docs/css/dropdown.css @@ -8,6 +8,8 @@ border: none; cursor: pointer; font-weight: 400; + position: relative; + z-index: 100; /* High z-index for the button */ } /* Dropdown button on hover & focus */ @@ -19,6 +21,7 @@ .dropdown { position: relative; display: inline-block; + z-index: 100; /* Ensure the container itself has a high z-index */ } /* Dropdown Content (Hidden by Default) */ @@ -29,7 +32,7 @@ min-width: 160px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.1); border: 1px solid var(--md-hopsworks-border); - z-index: 1; + z-index: 100; /* Very high z-index to ensure it appears above all content */ } /* Links inside the dropdown */ @@ -39,6 +42,8 @@ text-decoration: none; display: block; font-size: 0.8rem; + position: relative; + z-index: 100; /* Ensure links have high z-index too */ } /* Change color of dropdown links on hover */ diff --git a/docs/index.md b/docs/index.md index b70437968..7b1743e80 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,6 +3,7 @@ hide: - navigation - toc - title +full_width: true --- - -
-
-

Feature Store & MLOps Platform

-

Store, discover, and serve ML features and models

+ +
+
+

Hopsworks AI Platform Architecture

+

A comprehensive ML platform with a modular design approach for data storage, feature engineering, model management, and deployment

-
- -
-
- - - - - -

Feature Store

+
+
+
+

AI Lakehouse

+

Unified storage with table formats

- -
-
- Write API - Feature Groups - External Feature Groups +
+
+

Storage Connectors

+

Snowflake, BigQuery, Redshift, S3, ADLS

- -
- Read API - Feature Views - Training Data - Feature Vectors +
+

Table Format

+

Hudi tables with time travel capabilities

+
+
+

Compute Portability

+

Python, Spark, Flink, SQL

-
- -
- -
-
- - - - -

MLOps

-
- - - -
- - - - - - - Vector DB - - - - - - - - Lineage - - - - - - - - - Projects - +
+
+

MLOps Platform

+

Full machine learning lifecycle

-
-
- -
-
-
- - - - - -

Integrations

-
- - - -
- - 🔌 - JDBC - - - 📈 - BigQuery - - - ☁️ - S3 - - - ❄️ - Snowflake - +
+
+

Model Registry

+

Version, store, and manage ML models

+
+
+

Model Serving

+

KServe-based online and batch inference

+
+
+

GPU Management

+

Optimize training and inference workloads

+
+
+

Vector Database

+

Similarity search via OpenSearch

+
-
-
- - - - - - -

Deployment

+
+
+

Feature Store

+

Feature engineering and serving

- -
- - Azure - Azure - - - AWS - AWS - - - Google Cloud - Google Cloud - - - On-Premise - On-Premise - +
+
+

Feature Groups

+

Logical collections of features

+
+
+

Feature Views

+

Training data and inference vectors

+
+
+

Data Validation

+

Statistics, expectations and monitoring

+
+
+

Online Storage

+

High-throughput feature vectors via RonDB

+
- - -# Hopsworks: Feature Store & MLOps Platform - -Hopsworks is a modular data platform with a Python-centric Feature Store and comprehensive MLOps capabilities. Use it as a standalone Feature Store or leverage its full suite of tools to manage your entire ML lifecycle. - -## 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 in any Python, Spark, or Flink environment, either inside or outside Hopsworks. - -Use the Python frameworks you already know to build production feature pipelines: -- Compute aggregations in Pandas -- Validate feature data with Great Expectations -- Reduce dimensionality with embeddings and PCA -- Test feature logic end-to-end with PyTest -- Transform features with Scikit-Learn, TensorFlow, and PyTorch - -## Wide Range of Capabilities - -- **Feature Pipelines**: Support for Python, PySpark, Spark, Flink, and SQL -- **Storage Flexibility**: Store offline features in Hopsworks as Hudi tables or connect to external systems (Snowflake, Databricks, Redshift, BigQuery) -- **Online Serving**: Industry-leading throughput and availability with RonDB - -## MLOps on Hopsworks - -Hopsworks provides comprehensive model management through KServe: -- Feature/prediction logging to Kafka -- Secure, low-latency model deployments via Istio -- Model versioning with the Model Registry -- Vector database for similarity search through OpenSearch - -## Project-based Collaboration - -Hopsworks creates secure sandboxes for teams to collaborate and share ML assets: -- Fine-grained sharing across project boundaries -- End-to-end team responsibility from raw data to models -- Development, staging, and production environments -- Versioning, lineage, and provenance for all ML assets + +
+

Python-centric ML Platform

+

+ Hopsworks breaks the monolithic model development pipeline into separate feature and training pipelines, enabling both feature reuse and better tested ML assets. Use the frameworks you already know to build production pipelines, from feature engineering to model deployment. +

+
-## Available on Any Platform + +
+
+

Feature Store

+

Store, version, and serve machine learning features

+ +
+ +
+

Model Registry

+

Version and manage your ML models

+ +
+ +
+

Model Serving

+

Deploy models for online and batch inference

+ +
+ +
+

Data Lineage

+

Track data and model provenance

+ +
+ +
+

Compute Engines

+

Run workloads on various compute engines

+ +
+ +
+

Projects & Collaboration

+

Organize teams and ML assets

+ +
+
-Deploy Hopsworks anywhere: -- Cloud: AWS, Azure, GCP -- On-Premises: Ubuntu/Redhat compatible, including air-gapped environments -- Serverless: Fully managed platform for features and models + + -## Join the Community +# Hopsworks AI Platform -- Get help in the [Hopsworks Community](https://community.hopsworks.ai/) -- Follow us on [Twitter](https://twitter.com/hopsworks) -- Check out our [product releases](https://github.com/logicalclocks/hopsworks/releases) -- Join our [Slack channel](https://join.slack.com/t/public-hopsworks/shared_invite/zt-24fc3hhyq-VBEiN8UZlKsDrrLvtU4NaA) \ No newline at end of file +Hopsworks is a modular AI platform with a Python-centric Feature Store and comprehensive MLOps capabilities. \ No newline at end of file diff --git a/docs/js/inject-api-links.js b/docs/js/inject-api-links.js index 89082c67d..0865ab736 100644 --- a/docs/js/inject-api-links.js +++ b/docs/js/inject-api-links.js @@ -25,4 +25,18 @@ window.addEventListener("DOMContentLoaded", function () { 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"; } + + // Fix for API dropdown z-index issues + // Make sure the dropdown is higher in the stacking context than the content area + var apiDropdown = document.querySelector('.dropdown'); + if (apiDropdown) { + // Force the dropdown to have a higher stacking context by setting explicit z-index styles + apiDropdown.style.zIndex = "1000"; + + // Also ensure the content inside the dropdown has high z-index + var dropdownContent = apiDropdown.querySelector('.dropdown-content'); + if (dropdownContent) { + dropdownContent.style.zIndex = "1000"; + } + } }); diff --git a/docs/js/layout_improvement.js b/docs/js/layout_improvement.js index be218338d..de0a50bbb 100644 --- a/docs/js/layout_improvement.js +++ b/docs/js/layout_improvement.js @@ -12,4 +12,10 @@ document.addEventListener('DOMContentLoaded', function() { } }); } + + // 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'); + } }); diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 7fc85fb25..d401a27e9 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -5,4 +5,15 @@ Click here to go to latest. +{% endblock %} + +{% block extrahead %} + {{ super() }} + {% if page and page.meta and page.meta.full_width %} + + {% endif %} {% endblock %} \ No newline at end of file From d8cfdf471982417a9e53b9734ceae9a6aee39ba8 Mon Sep 17 00:00:00 2001 From: MagicLex Date: Tue, 4 Mar 2025 11:57:05 +0200 Subject: [PATCH 04/24] UI and UX improvements across the documentation site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed version dropdown to consistently show the correct version options - Updated API dropdown and navigation to use correct URLs (linking to /latest instead of /dev) - Enhanced homepage with modern hero section and improved visual hierarchy - Fixed color inconsistencies and removed blue gradients from dark mode - Improved navigation styling and color consistency throughout the site - Added responsive design improvements for mobile devices - Fixed z-index issues with overlapping elements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/css/custom.css | 549 ++++++++++++++++++++++++++++++++---- docs/css/dropdown.css | 110 +++++--- docs/index.md | 31 +- docs/js/dropdown.js | 184 +++++++++++- docs/js/inject-api-links.js | 67 ++--- docs/overrides/main.html | 45 +++ 6 files changed, 857 insertions(+), 129 deletions(-) diff --git a/docs/css/custom.css b/docs/css/custom.css index 7cadad8e6..59c0ba97e 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -105,6 +105,35 @@ 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); @@ -146,6 +175,42 @@ color: var(--md-hopsworks-primary); } +/* Fix blue highlight in sidebar */ +.md-nav__item .md-nav__link--active { + color: var(--md-hopsworks-primary); + font-weight: 500; +} + +/* Remove blue background from sidebar active item */ +.md-nav__item--active>.md-nav__link { + color: var(--md-hopsworks-primary); +} + +/* Remove sidebar item shadow */ +[dir=ltr] .md-nav__item--active>.md-nav__link { + box-shadow: none !important; + background-color: transparent !important; + background-image: none !important; +} + +/* Fix sidebar blue gradient in dark mode */ +.md-nav__item .md-nav__link[data-md-state=active] { + background-color: transparent !important; + background-image: none !important; + color: var(--md-hopsworks-primary); +} + +.md-nav__item--nested .md-nav__link { + background-image: none !important; +} + +/* Fix tab blue gradient in dark mode */ +.md-tabs__link--active, +.md-tabs__link:hover { + background-image: none !important; + background-color: transparent !important; +} + .md-sidebar { background-color: var(--md-hopsworks-background); } @@ -314,10 +379,30 @@ 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-typeset .admonition-title { font-weight: 600; + background-color: var(--md-hopsworks-background) !important; + background-image: none !important; +} + +/* Fix admonition icons */ +.md-typeset .admonition-title::before { + color: var(--md-hopsworks-primary); +} + +/* 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 */ @@ -327,6 +412,11 @@ --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"] { @@ -335,6 +425,16 @@ --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 */ @@ -360,50 +460,188 @@ /* Make sure index and content pages have consistent widths */ .md-content__inner { - max-width: 1000px; - margin: 0 auto; position: relative; z-index: 1; /* Lower z-index for content */ } +/* Custom version dropdown that appears in the header */ + +.md-main__inner{ + margin-top:0px; +} +.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; +} + +.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-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); +} + +.md-version-dropdown a:last-child { + border-bottom: none; +} + +.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; +} + +/* 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 table of contents color inconsistencies */ +.md-nav--secondary .md-nav__link { + color: var(--md-hopsworks-text); +} + +.md-nav--secondary .md-nav__link:hover, +.md-nav--secondary .md-nav__link:focus, +.md-nav--secondary .md-nav__link--active { + color: var(--md-hopsworks-primary); +} + +/* 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: 1000px; - margin: 20px auto 40px; + margin: 40px auto 60px; position: relative; display: flex; flex-direction: column; - gap: 15px; + gap: 25px; + 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: left; - margin-bottom: 15px; + text-align: center; + margin-bottom: 20px; } .arch-title { - font-size: 1.5rem; - font-weight: 500; - margin-bottom: 5px; + font-size: 1.8rem; + font-weight: 600; + margin-bottom: 10px; color: var(--md-hopsworks-text); } .arch-subtitle { - font-size: 0.95rem; + font-size: 1rem; color: var(--md-hopsworks-text-light); - margin: 0; + margin: 0 auto; + max-width: 700px; + line-height: 1.5; } .architecture-tiers { display: flex; - gap: 15px; - height: 300px; + gap: 25px; + min-height: 380px; } .architecture-tier { @@ -412,24 +650,35 @@ flex-direction: column; border: 1px solid var(--md-hopsworks-border); background-color: var(--md-hopsworks-card-bg); + border-radius: var(--md-hopsworks-radius); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; +} + +.architecture-tier:hover { + border-color: var(--md-hopsworks-primary); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + transform: translateY(-5px); } .tier-header { - padding: 15px; + padding: 20px; border-bottom: 1px solid var(--md-hopsworks-border); background-color: var(--md-hopsworks-background); + border-top-left-radius: var(--md-hopsworks-radius); + border-top-right-radius: var(--md-hopsworks-radius); } .tier-title { - font-size: 1.1rem; - font-weight: 500; + font-size: 1.2rem; + font-weight: 600; margin: 0; color: var(--md-hopsworks-text); } .tier-description { - font-size: 0.85rem; - margin: 5px 0 0 0; + font-size: 0.9rem; + margin: 8px 0 0 0; color: var(--md-hopsworks-text-light); } @@ -437,131 +686,319 @@ flex: 1; display: flex; flex-direction: column; - padding: 15px; - gap: 10px; + padding: 20px; + gap: 15px; overflow-y: auto; } .tier-component { - padding: 10px; + padding: 15px; border: 1px solid var(--md-hopsworks-border); background-color: var(--md-hopsworks-background); + border-radius: var(--md-hopsworks-radius); + transition: all 0.2s ease; +} + +.tier-component:hover { + border-color: var(--md-hopsworks-primary); + transform: translateY(-2px); } .component-title { - font-size: 0.9rem; + font-size: 1rem; font-weight: 500; - margin: 0 0 5px 0; + margin: 0 0 8px 0; color: var(--md-hopsworks-text); } .component-description { - font-size: 0.8rem; + font-size: 0.85rem; margin: 0; color: var(--md-hopsworks-text-light); + line-height: 1.4; +} + +/* 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 { + background: linear-gradient(180deg, var(--md-hopsworks-card-bg) 0%, var(--md-hopsworks-background) 100%); + padding: 50px 20px; + text-align: center; + margin-bottom: 40px; + border-bottom: 1px solid var(--md-hopsworks-border); } -/* Interlude Text */ -.interlude-text { - max-width: 1000px; - margin: 30px auto 40px; - text-align: left; +.hero-content { + max-width: 800px; + margin: 0 auto; } -.interlude-title { - font-size: 1.4rem; - font-weight: 500; - margin-bottom: 10px; +.hero-title { + font-size: 2.5rem !important; + font-weight: 600; + margin-bottom: 15px; color: var(--md-hopsworks-text); + line-height: 1.2; } -.interlude-description { - font-size: 0.95rem; +.hero-subtitle { + font-size: 1.2rem; color: var(--md-hopsworks-text-light); + margin-bottom: 30px; line-height: 1.5; } +.hero-buttons { + display: flex; + justify-content: center; + gap: 15px; + margin-top: 25px; +} + +.hero-button { + display: inline-block; + padding: 12px 24px; + font-size: 1rem; + font-weight: 500; + text-decoration: none; + border-radius: var(--md-hopsworks-radius); + transition: all 0.2s ease; +} + +.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: 800px; + 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: 800px; + margin: 40px auto 60px; + 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; +} + /* Feature Navigation Grid */ .feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); - gap: 20px; - margin: 30px auto; + gap: 25px; + margin: 30px auto 60px; max-width: 1000px; + padding: 0 20px; } .feature-card { border: 1px solid var(--md-hopsworks-border); background-color: var(--md-hopsworks-card-bg); - padding: 25px; + padding: 30px; transition: all 0.2s ease; + border-radius: var(--md-hopsworks-radius); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + display: flex; + flex-direction: column; } .feature-card:hover { border-color: var(--md-hopsworks-primary); + transform: translateY(-3px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .feature-title { - font-size: 1.1rem; - font-weight: 500; - margin-bottom: 10px; + 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.85rem; + font-size: 0.9rem; color: var(--md-hopsworks-text-light); - margin-bottom: 15px; + margin-bottom: 20px; + line-height: 1.5; + flex-grow: 1; } .feature-links { - margin-top: 10px; + margin-top: auto; } .feature-link { display: block; - font-size: 0.8rem; + font-size: 0.85rem; color: var(--md-hopsworks-primary); - margin-bottom: 5px; + margin-bottom: 8px; text-decoration: none; + transition: all 0.2s ease; + position: relative; + padding-left: 12px; +} + +.feature-link::before { + content: "→"; + position: absolute; + left: -4px; + transition: transform 0.2s ease; } .feature-link:hover { - text-decoration: underline; + color: var(--md-hopsworks-secondary); + transform: translateX(2px); +} + +.feature-link:hover::before { + transform: translateX(2px); } /* Deployment Options */ .deployment-options { display: grid; grid-template-columns: repeat(4, 1fr); - gap: 15px; - margin: 30px auto; + gap: 20px; + margin: 30px auto 60px; max-width: 1000px; + padding: 0 20px; } .deployment-option { border: 1px solid var(--md-hopsworks-border); background-color: var(--md-hopsworks-card-bg); - padding: 20px; + padding: 25px 20px; text-align: center; - transition: all 0.2s ease; + transition: all 0.3s ease; + border-radius: var(--md-hopsworks-radius); + text-decoration: none; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); } .deployment-option:hover { border-color: var(--md-hopsworks-primary); + transform: translateY(-3px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .placeholder-icon { - width: 40px; - height: 40px; - background-color: var(--md-hopsworks-background); - margin: 0 auto 10px; + width: 50px; + height: 50px; + background-color: var(--md-hopsworks-primary); + opacity: 0.2; + margin: 0 auto 15px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; +} + +.deployment-option:hover .placeholder-icon { + background-color: var(--md-hopsworks-primary); + opacity: 0.3; } .deployment-title { - font-size: 0.9rem; + font-size: 1rem; font-weight: 500; color: var(--md-hopsworks-text); + margin: 0; } /* Inner MLOps Components Grid */ diff --git a/docs/css/dropdown.css b/docs/css/dropdown.css index 8b576801e..2a0cc8498 100644 --- a/docs/css/dropdown.css +++ b/docs/css/dropdown.css @@ -1,58 +1,104 @@ -/* Dropdown Button */ -.dropbtn { +/* 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; - font-size: 0.8rem; + 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: 400; - position: relative; - z-index: 100; /* High z-index for the button */ + 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 */ } -/* Dropdown button on hover & focus */ -.dropbtn:hover, .dropbtn:focus { - color: var(--md-hopsworks-primary); +/* 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; } -/* The dropdown container */ -.dropdown { - position: relative; - display: inline-block; - z-index: 100; /* Ensure the container itself has a high z-index */ +#api-modal-btn:hover { + color: var(--md-hopsworks-primary); + opacity: 1; /* Match the opacity of md-tabs__link:hover */ } -/* Dropdown Content (Hidden by Default) */ -.dropdown-content { +/* The dropdown container (no overlay) */ +#api-modal-container { display: none; - position: absolute; + position: fixed; + z-index: 9999; +} + +/* Modal content box */ +#api-modal-content { + position: relative; + width: 220px; background-color: var(--md-hopsworks-card-bg); - min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.1); border: 1px solid var(--md-hopsworks-border); - z-index: 100; /* Very high z-index to ensure it appears above all content */ + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + padding: 0; } -/* Links inside the dropdown */ -.dropdown-content a { +/* Links inside the modal */ +#api-modal-content a { color: var(--md-hopsworks-text); - padding: 12px 16px; + padding: 10px 15px; text-decoration: none; display: block; - font-size: 0.8rem; - position: relative; - z-index: 100; /* Ensure links have high z-index too */ + 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 { +#api-modal-content a:last-child { + border-bottom: none; +} + +/* Change color of links on hover */ +#api-modal-content a:hover { background-color: var(--md-hopsworks-background); color: var(--md-hopsworks-primary); } -/* Show the dropdown menu on hover */ -.dropdown:hover .dropdown-content { - display: block; +/* 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/index.md b/docs/index.md index 7b1743e80..73db6290f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,11 +12,23 @@ full_width: true } + +
+
+

Hopsworks AI Platform

+

A production-grade ML platform with a Python-centric Feature Store and enterprise MLOps capabilities

+ +
+
+
-

Hopsworks AI Platform Architecture

-

A comprehensive ML platform with a modular design approach for data storage, feature engineering, model management, and deployment

+

Platform Architecture

+

A comprehensive ML platform with modular components for the entire machine learning lifecycle

@@ -93,11 +105,16 @@ full_width: true
- -
-

Python-centric ML Platform

-

- Hopsworks breaks the monolithic model development pipeline into separate feature and training pipelines, enabling both feature reuse and better tested ML assets. Use the frameworks you already know to build production pipelines, from feature engineering to model deployment. + +

+
+
+ + +
+

Modern ML Platform for Every Team

+

+ Hopsworks breaks the monolithic ML development pipeline into separate feature and training pipelines, enabling both feature reuse and better tested ML assets. Use the frameworks you already know to build production pipelines, from feature engineering to model deployment.

diff --git a/docs/js/dropdown.js b/docs/js/dropdown.js index 4f0a7e8a7..1c03c1f9b 100644 --- a/docs/js/dropdown.js +++ b/docs/js/dropdown.js @@ -1,3 +1,183 @@ -document.getElementsByClassName("md-tabs__link")[6].style.display = "none"; -document.getElementsByClassName("md-tabs__link")[8].style.display = "none"; +document.addEventListener('DOMContentLoaded', function() { + // Reorganize navigation links + const tabsContainer = document.querySelector('.md-tabs__list'); + if (!tabsContainer) return; // Safety check + + const navItems = Array.from(tabsContainer.children); + + // Find navigation items we want to reorder + const gettingStartedIndex = navItems.findIndex(item => + item.textContent.trim().includes('Getting Started') + ); + + const communityIndex = navItems.findIndex(item => + item.textContent.trim().includes('Community') + ); + + const apiLinkIndex = navItems.findIndex(item => + item.textContent.trim().includes('API') + ); + + // Only proceed if we found items to reposition + if (apiLinkIndex !== -1) { + // Create API dropdown replacement + setupApiDropdown(tabsContainer, apiLinkIndex); + + // Reorder external links if found + if (gettingStartedIndex !== -1 && communityIndex !== -1) { + reorderNavLinks(tabsContainer, gettingStartedIndex, communityIndex); + } + } +}); +/** + * 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'); + } + }); +} + +/** + * Reorders navigation links to move external links to the end + */ +function reorderNavLinks(tabsContainer, gettingStartedIndex, communityIndex) { + // To avoid index shifting, we need to adjust indices when removing + // Clone the items first so we can re-add them in the right order + const gettingStartedItem = tabsContainer.children[gettingStartedIndex].cloneNode(true); + const communityItem = tabsContainer.children[communityIndex].cloneNode(true); + + // Check if there's an API item which we created + // Note: :has() selector might not be supported in all browsers, using alternative + const apiItem = Array.from(tabsContainer.querySelectorAll('li')).find(li => + li.querySelector('#api-modal-btn') + ); + + // Remove items (in reverse order to avoid index shifting) + if (communityIndex > gettingStartedIndex) { + tabsContainer.removeChild(tabsContainer.children[communityIndex]); + tabsContainer.removeChild(tabsContainer.children[gettingStartedIndex]); + } else { + tabsContainer.removeChild(tabsContainer.children[gettingStartedIndex]); + tabsContainer.removeChild(tabsContainer.children[communityIndex < gettingStartedIndex ? communityIndex : communityIndex - 1]); + } + + // If we have our API item, move it as well + if (apiItem) { + tabsContainer.removeChild(apiItem); + } + + // Add items in the desired order at the end + if (apiItem) { + tabsContainer.appendChild(apiItem); + } + tabsContainer.appendChild(gettingStartedItem); + tabsContainer.appendChild(communityItem); +} \ No newline at end of file diff --git a/docs/js/inject-api-links.js b/docs/js/inject-api-links.js index 0865ab736..11fbd7da8 100644 --- a/docs/js/inject-api-links.js +++ b/docs/js/inject-api-links.js @@ -2,41 +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]; } - // 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"; } - // Fix for API dropdown z-index issues - // Make sure the dropdown is higher in the stacking context than the content area - var apiDropdown = document.querySelector('.dropdown'); - if (apiDropdown) { - // Force the dropdown to have a higher stacking context by setting explicit z-index styles - apiDropdown.style.zIndex = "1000"; - - // Also ensure the content inside the dropdown has high z-index - var dropdownContent = apiDropdown.querySelector('.dropdown-content'); - if (dropdownContent) { - dropdownContent.style.zIndex = "1000"; + // 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 } } }); diff --git a/docs/overrides/main.html b/docs/overrides/main.html index d401a27e9..5e901f72e 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -16,4 +16,49 @@ }); {% endif %} +{% endblock %} + +{% block scripts %} + {{ super() }} + {% endblock %} \ No newline at end of file From 9921ad8a8a6b9de4715dd53abfa9cbf6adf3f5a9 Mon Sep 17 00:00:00 2001 From: MagicLex Date: Tue, 4 Mar 2025 12:08:24 +0200 Subject: [PATCH 05/24] Add zoomable images functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added ability to click on documentation images to see an enlarged version - Implemented smooth image modal with transitions and loading indicators - Added zoom icon indicators that appear on hover for better discoverability - Ensured accessibility with keyboard navigation (Esc to close) and ARIA attributes - Excluded small images, icons, and images in links from zoom functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/css/custom.css | 141 ++++++++++++++++++++++++++++- docs/js/layout_improvement.js | 166 ++++++++++++++++++++++++++++++++++ 2 files changed, 306 insertions(+), 1 deletion(-) diff --git a/docs/css/custom.css b/docs/css/custom.css index 59c0ba97e..d5c2e2182 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -1025,4 +1025,143 @@ .component-description { font-size: 0.8rem; color: var(--md-hopsworks-text-light); -} \ No newline at end of file +}/* 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; +} diff --git a/docs/js/layout_improvement.js b/docs/js/layout_improvement.js index de0a50bbb..a9d8e54f4 100644 --- a/docs/js/layout_improvement.js +++ b/docs/js/layout_improvement.js @@ -18,4 +18,170 @@ document.addEventListener('DOMContentLoaded', function() { 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'; + } + }); +} From ea47456dd0e896ec2417c495ed2bd49b5f5d18a0 Mon Sep 17 00:00:00 2001 From: MagicLex Date: Tue, 4 Mar 2025 12:09:45 +0200 Subject: [PATCH 06/24] additional fixes --- docs/index.md | 2 +- docs/overrides/main.html | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 73db6290f..3472ed22f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,7 +15,7 @@ full_width: true
-

Hopsworks AI Platform

+

Hopsworks AI Lakehouse

A production-grade ML platform with a Python-centric Feature Store and enterprise MLOps capabilities

Try Quickstart diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 5e901f72e..b3c7f4f3e 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -20,6 +20,7 @@ {% block scripts %} {{ super() }} + +