/
vshmidt
/
streamlit
Обзор
Документация
Войти
/
vshmidt
/
streamlit
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
frontend/app/src/components/Sidebar/styled-components.ts
250 строк
8 KB
Rahul Dogra
Add support for material icons and emojis in `st.logo` (#13416)
27 янв 2026, 05:07
Не верифицирован
27 янв 2026, 05:07
a27d52d
Код
Авторство
О чём код?
/** * Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import styled from "@emotion/styled" import { EmotionTheme, hasLightBackgroundColor } from "@streamlit/lib" /** * Returns the horizontal spacing for the sidebar, taking into consideration * the scrollbar gutters (one on each side) which are present when the OS * doesn't support overlay scrollbars. * * @param theme The theme to use. * @returns The horizontal spacing for the sidebar. */ export const getSidebarHorizontalSpacing = ( theme: EmotionTheme, scrollbarGutterSize: number ): string => { // This should be max(0px, ...), but there's a Chrome bug that // causes content to clip when scrollbar-gutter is set to "stable both-edges". // So we change the min from 0px to scrollbarGutterSize to account for that. // Chrome bug: https://issues.chromium.org/issues/40064879 return `max( ${scrollbarGutterSize}px, calc(${theme.spacing.xl} - ${scrollbarGutterSize}px) )` } export interface StyledSidebarProps { isCollapsed: boolean adjustTop: boolean sidebarWidth: string windowInnerWidth: number } export const StyledSidebar = styled.section<StyledSidebarProps>( ({ theme, isCollapsed, adjustTop, sidebarWidth, windowInnerWidth }) => { const minWidth = isCollapsed ? 0 : Math.min(200, windowInnerWidth) const maxWidth = isCollapsed ? 0 : Math.min(600, windowInnerWidth * 0.9) return { position: "relative", // Nudge the sidebar by 2px so the header decoration doesn't go below it top: adjustTop ? theme.sizes.headerDecorationHeight : theme.spacing.none, backgroundColor: theme.colors.bgColor, // Since the sidebar can have a different theme (+ background) // we need to explicitly set the font color and color scheme // here again so that it is inherited correctly by all sidebar elements: color: theme.colors.bodyText, colorScheme: hasLightBackgroundColor(theme) ? "light" : "dark", zIndex: theme.zIndices.header + 1, minWidth, maxWidth, transform: isCollapsed ? `translateX(-${sidebarWidth}px)` : "none", transition: "transform 300ms, min-width 300ms, max-width 300ms", "&:focus": { outline: "none", }, [`@media (max-width: ${theme.breakpoints.md})`]: { boxShadow: isCollapsed ? "-2rem 0 2rem 2rem transparent" : theme.shadows.sidebar, }, [`@media print`]: { display: isCollapsed ? "none" : "initial", // set to auto, otherwise the sidebar does not take up the whole page height: "auto !important", // set maxHeight to little bit less than 100%, otherwise the sidebar might start a mostly blank page maxHeight: "99%", // on Chrome, sth. adds a box-shadow in printing mode which looks weird boxShadow: "none", }, } } ) export interface StyledSidebarUserContentProps { hasPageNavAbove: boolean } export const StyledSidebarUserContent = styled.div<StyledSidebarUserContentProps>(({ hasPageNavAbove, theme }) => ({ paddingTop: hasPageNavAbove ? theme.spacing.twoXL : 0, paddingBottom: theme.sizes.sidebarTopSpace, })) export interface StyledSidebarContentProps { scrollbarGutterSize: number } export const StyledSidebarContent = styled.div<StyledSidebarContentProps>( ({ theme, scrollbarGutterSize }) => ({ position: "relative", height: "100%", width: "100%", overflow: "auto", /** * Ensure that space is reserved for scrollbars, even when they are not * visible. This is necessary to prevent layout shifts when the scrollbars * appear and disappear. * * We utilize both-edges so that things look visually centered and aligned. * * @see https://github.com/streamlit/streamlit/issues/10310 */ scrollbarGutter: "stable both-edges", paddingLeft: getSidebarHorizontalSpacing(theme, scrollbarGutterSize), paddingRight: getSidebarHorizontalSpacing(theme, scrollbarGutterSize), }) ) export const RESIZE_HANDLE_WIDTH = "8px" export const StyledResizeHandle = styled.div(({ theme }) => ({ position: "absolute", width: RESIZE_HANDLE_WIDTH, height: "100%", cursor: "col-resize", zIndex: theme.zIndices.sidebarMobile, backgroundImage: theme.showSidebarBorder ? `linear-gradient(to right, transparent 20%, ${theme.colors.borderColor} 28%, transparent 36%)` : "none", "&:hover": { backgroundImage: `linear-gradient(to right, transparent 20%, ${theme.colors.borderColor} 28%, transparent 44%)`, }, })) export const StyledSidebarHeaderContainer = styled.div(({ theme }) => ({ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: theme.spacing.lg, height: theme.sizes.headerHeight, })) export const StyledLogoLink = styled.a({ "&:hover": { opacity: "0.7", }, }) export const StyledLogoButton = styled.button({ // Reset button styles background: "none", border: "none", padding: 0, cursor: "pointer", "&:hover": { opacity: "0.7", }, }) export interface StyledLogoProps { size: string sidebarWidth?: string } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: Replace 'any' with a more specific type. function translateLogoHeight(theme: any, size: string): string { if (size === "small") { return theme.sizes.smallLogoHeight } else if (size === "large") { return theme.sizes.largeLogoHeight } // Default logo size return theme.sizes.defaultLogoHeight } export const StyledLogo = styled.img<StyledLogoProps>(({ theme, size }) => ({ height: translateLogoHeight(theme, size), // Extra margin to align small logo with sidebar collapse arrow marginTop: size == "small" ? theme.spacing.xs : theme.spacing.twoXS, marginBottom: size == "small" ? theme.spacing.xs : theme.spacing.twoXS, marginLeft: theme.spacing.none, zIndex: theme.zIndices.header, objectFit: "contain", objectPosition: "left", verticalAlign: "middle", maxWidth: `100%`, })) export const StyledIconLogo = styled.div<StyledLogoProps>( ({ theme, size }) => ({ display: "flex", alignItems: "center", justifyContent: "flex-start", height: translateLogoHeight(theme, size), marginTop: size == "small" ? theme.spacing.xs : theme.spacing.twoXS, marginBottom: size == "small" ? theme.spacing.xs : theme.spacing.twoXS, marginLeft: theme.spacing.none, zIndex: theme.zIndices.header, fontSize: translateLogoHeight(theme, size), lineHeight: theme.lineHeights.none, color: theme.colors.bodyText, }) ) export const StyledNoLogoSpacer = styled.div(({ theme }) => ({ height: theme.sizes.largeLogoHeight, })) export interface StyledCollapseSidebarButtonProps { showSidebarCollapse: boolean } export const StyledCollapseSidebarButton = styled.div<StyledCollapseSidebarButtonProps>( ({ showSidebarCollapse, theme }) => { return { display: "inline", visibility: showSidebarCollapse ? "visible" : "hidden", marginLeft: theme.spacing.sm, transition: "left 300ms", transitionDelay: "left 300ms", color: hasLightBackgroundColor(theme) ? theme.colors.fadedText60 : theme.colors.bodyText, lineHeight: "0", [`@media print`]: { // Always hide the collapse button on print: visibility: "hidden", }, [`@media (max-width: ${theme.breakpoints.sm})`]: { // Always show the collapse button on small screens: visibility: "visible", }, } } )