diff --git a/cli/util.py b/cli/util.py index bc30b1a..5e1783b 100644 --- a/cli/util.py +++ b/cli/util.py @@ -164,7 +164,7 @@ def build_ui(): status("Starting new UI build...") - if params.general.developer_mode: + if params.developer_mode: dev_mode = "production" else: dev_mode = "development" @@ -172,8 +172,8 @@ def build_ui(): try: success = asyncio.run( build_frontend( - dev_mode=params.general.developer_mode, - dev_url=f"http://localhost:{str(params.general.listen_port)}/api/", + dev_mode=params.developer_mode, + dev_url=f"http://localhost:{str(params.listen_port)}/api/", prod_url="/api/", params=frontend_params, force=True, diff --git a/hyperglass/configuration/__init__.py b/hyperglass/configuration/__init__.py index 43b5304..3de1edd 100644 --- a/hyperglass/configuration/__init__.py +++ b/hyperglass/configuration/__init__.py @@ -332,19 +332,6 @@ def _build_vrfs(): return vrfs -def _build_queries(): - """Build a dict of supported query types and their display names. - - Returns: - {list} -- Supported query list - """ - queries = [] - for query in SUPPORTED_QUERY_TYPES: - query_params = getattr(params.queries, query) - queries.append({"name": query, "display_name": query_params.display_name}) - return queries - - content_params = json.loads( params.json(include={"primary_asn", "org_name", "site_title", "site_description"}) ) @@ -409,7 +396,6 @@ content_terms = asyncio.run( content_credit = CREDIT vrfs = _build_vrfs() -queries = _build_queries() networks = _build_networks() frontend_networks = _build_frontend_networks() frontend_devices = _build_frontend_devices() @@ -421,19 +407,12 @@ _frontend_fields = { "google_analytics": ..., "site_description": ..., "web": ..., - "queries": { - "bgp_route": {"enable", "display_name"}, - "bgp_community": {"enable", "display_name"}, - "bgp_aspath": {"enable", "display_name"}, - "ping": {"enable", "display_name"}, - "traceroute": {"enable", "display_name"}, - }, "messages": ..., } _frontend_params = params.dict(include=_frontend_fields) _frontend_params.update( { - "queries": queries, + "queries": {**params.queries.map, "list": params.queries.list}, "devices": frontend_devices, "networks": networks, "vrfs": vrfs, diff --git a/hyperglass/configuration/models/params.py b/hyperglass/configuration/models/params.py index c04d9e6..0535136 100644 --- a/hyperglass/configuration/models/params.py +++ b/hyperglass/configuration/models/params.py @@ -32,7 +32,7 @@ class Params(HyperglassModel): debug: StrictBool = False developer_mode: StrictBool = False primary_asn: Union[StrictInt, StrictStr] = "65001" - org_name: StrictStr = "The Company" + org_name: StrictStr = "Beloved Hyperglass User" site_title: StrictStr = "hyperglass" site_description: StrictStr = "{org_name} Network Looking Glass" site_keywords: List[StrictStr] = [ diff --git a/hyperglass/configuration/models/queries.py b/hyperglass/configuration/models/queries.py index 9d8e012..261c18c 100644 --- a/hyperglass/configuration/models/queries.py +++ b/hyperglass/configuration/models/queries.py @@ -8,6 +8,7 @@ from pydantic import constr # Project Imports from hyperglass.configuration.models._utils import HyperglassModel +from hyperglass.constants import SUPPORTED_QUERY_TYPES class BgpCommunity(HyperglassModel): @@ -77,6 +78,42 @@ class Queries(HyperglassModel): "Prefix length must be smaller than /{m}. {i} is too specific." ) + @property + def map(self): + """Return a dict of all query display names, internal names, and enable state. + + Returns: + {dict} -- Dict of queries. + """ + _map = {} + for query in SUPPORTED_QUERY_TYPES: + query_obj = getattr(self, query) + _map[query] = { + "name": query, + "display_name": query_obj.display_name, + "enable": query_obj.enable, + } + return _map + + @property + def list(self): + """Return a list of all query display names, internal names, and enable state. + + Returns: + {list} -- Dict of queries. + """ + _list = [] + for query in SUPPORTED_QUERY_TYPES: + query_obj = getattr(self, query) + _list.append( + { + "name": query, + "display_name": query_obj.display_name, + "enable": query_obj.enable, + } + ) + return _list + bgp_route: BgpRoute = BgpRoute() bgp_community: BgpCommunity = BgpCommunity() bgp_aspath: BgpAsPath = BgpAsPath() diff --git a/hyperglass/configuration/models/web.py b/hyperglass/configuration/models/web.py index 584c5fb..8b4d902 100644 --- a/hyperglass/configuration/models/web.py +++ b/hyperglass/configuration/models/web.py @@ -18,201 +18,242 @@ from pydantic.color import Color # Project Imports from hyperglass.configuration.models._utils import HyperglassModel from hyperglass.configuration.models.opengraph import OpenGraph +from hyperglass.constants import FUNC_COLOR_MAP -class Web(HyperglassModel): - """Validation model for params.branding.""" +class Analytics(HyperglassModel): + """Validation model for Google Analytics.""" - class Analytics(HyperglassModel): - """Validation model for Google Analytics.""" + enable: StrictBool = False + id: Optional[StrictStr] - enable: StrictBool = False - id: Optional[StrictStr] + @validator("id") + def validate_id(cls, value, values): + """Ensure ID is set if analytics is enabled. - @validator("id") - def validate_id(cls, value, values): - """Ensure ID is set if analytics is enabled. + Arguments: + value {str|None} -- Google Analytics ID + values {[type]} -- Already-validated model parameters - Arguments: - value {str|None} -- Google Analytics ID - values {[type]} -- Already-validated model parameters + Raises: + ValueError: Raised if analytics is enabled but no ID is set. - Raises: - ValueError: Raised if analytics is enabled but no ID is set. + Returns: + {str|None} -- Google Analytics ID if enabled. + """ + if values["enable"] and value is None: + raise ValueError("Analytics is enabled, but no ID is set.") + return value - Returns: - {str|None} -- Google Analytics ID if enabled. - """ - if values["enable"] and value is None: - raise ValueError("Analytics is enabled, but no ID is set.") - return value + +class Credit(HyperglassModel): + """Validation model for developer credit.""" + + enable: StrictBool = True + + +class ExternalLink(HyperglassModel): + """Validation model for external link.""" + + enable: StrictBool = True + title: StrictStr = "PeeringDB" + url: HttpUrl = "https://www.peeringdb.com/AS{primary_asn}" + + +class Font(HyperglassModel): + """Validation model for params.branding.font.""" + + class Primary(HyperglassModel): + """Validation model for params.branding.font.primary.""" + + name: StrictStr = "Nunito" + size: StrictStr = "1rem" + + class Mono(HyperglassModel): + """Validation model for params.branding.font.mono.""" + + name: StrictStr = "Fira Code" + size: StrictStr = "87.5%" + + primary: Primary = Primary() + mono: Mono = Mono() + + +class HelpMenu(HyperglassModel): + """Validation model for generic help menu.""" + + enable: StrictBool = True + file: Optional[FilePath] + title: StrictStr = "Help" + + +class Logo(HyperglassModel): + """Validation model for logo configuration.""" + + light: Optional[FilePath] + dark: Optional[FilePath] + width: StrictInt = 384 + height: Optional[StrictInt] + favicons: StrictStr = "ui/images/favicons/" + + @validator("favicons") + def favicons_trailing_slash(cls, value): + """If the favicons path does not end in a '/', append it.""" + chars = list(value) + if chars[len(chars) - 1] != "/": + chars.append("/") + return "".join(chars) + + @root_validator(pre=True) + def validate_logo_model(cls, values): + """Set default opengraph image location. + + Arguments: + values {dict} -- Unvalidated model + + Returns: + {dict} -- Modified model + """ + logo_light = values.get("light") + logo_dark = values.get("dark") + default_logo_light = ( + Path(__file__).parent.parent.parent / "static/images/hyperglass-light.png" + ) + default_logo_dark = ( + Path(__file__).parent.parent.parent / "static/images/hyperglass-dark.png" + ) + + # Use light logo as dark logo if dark logo is undefined. + if logo_light is not None and logo_dark is None: + values["dark"] = logo_light + + # Use dark logo as light logo if light logo is undefined. + if logo_dark is not None and logo_light is None: + values["light"] = logo_dark + + # Set default logo paths if logo is undefined. + if logo_light is None and logo_dark is None: + values["light"] = default_logo_light + values["dark"] = default_logo_dark + + return values + + @validator("light", "dark") + def validate_logos(cls, value): + """Convert file path to URL path. + + Arguments: + value {FilePath} -- Path to logo file. + + Returns: + {str} -- Formatted logo path + """ + return "".join(str(value).split("static")[1::]) + + class Config: + """Override pydantic config.""" + + fields = {"logo_path": "path"} + + +class Terms(HyperglassModel): + """Validation model for terms & conditions.""" + + enable: StrictBool = True + file: Optional[FilePath] + title: StrictStr = "Terms" + + +class Text(HyperglassModel): + """Validation model for params.branding.text.""" + + title_mode: constr(regex=("logo_only|text_only|logo_title|all")) = "logo_only" + title: StrictStr = "hyperglass" + subtitle: StrictStr = "AS{primary_asn}" + query_location: StrictStr = "Location" + query_type: StrictStr = "Query Type" + query_target: StrictStr = "Target" + query_vrf: StrictStr = "Routing Table" + fqdn_tooltip: StrictStr = "Use {protocol}" # Formatted by Javascript + cache: StrictStr = "Results will be cached for {timeout} {period}." + + class Error404(HyperglassModel): + """Validation model for 404 Error Page.""" + + title: StrictStr = "Error" + subtitle: StrictStr = "{uri} isn't a thing" + button: StrictStr = "Home" + + class Error500(HyperglassModel): + """Validation model for 500 Error Page.""" + + title: StrictStr = "Error" + subtitle: StrictStr = "Something Went Wrong" + button: StrictStr = "Home" + + error404: Error404 = Error404() + error500: Error500 = Error500() + + +class Theme(HyperglassModel): + """Validation model for theme variables.""" class Colors(HyperglassModel): - """Validation model for params.colors.""" + """Validation model for theme colors.""" - primary: Color = "#40798c" - secondary: Color = "#330036" - danger: Color = "#a21024" - warning: Color = "#eec643" - light: Color = "#fbfffe" - dark: Color = "#383541" - background: Color = "#fbfffe" + black: Color = "#262626" + white: Color = "#f7f7f7" + gray: Color = "#c1c7cc" + red: Color = "#d84b4b" + orange: Color = "ff6b35" + yellow: Color = "#edae49" + green: Color = "#35b246" + blue: Color = "#314cb6" + teal: Color = "#35b299" + cyan: Color = "#118ab2" + pink: Color = "#f2607d" + purple: Color = "#8d30b5" + primary: Optional[Color] + secondary: Optional[Color] + success: Optional[Color] + warning: Optional[Color] + error: Optional[Color] + danger: Optional[Color] + + @validator(*FUNC_COLOR_MAP.keys(), pre=True, always=True) + def validate_colors(cls, value, values, field): + """Set default functional color mapping. + + Arguments: + value {str|None} -- Functional color + values {str} -- Already-validated colors + + Returns: + {str} -- Mapped color. + """ + + if value is None: + default_color = FUNC_COLOR_MAP[field.name] + value = str(values[default_color]) + return value def dict(self, *args, **kwargs): """Return dict for colors only.""" - _dict = {} - for k, v in self.__dict__.items(): - _dict.update({k: v.as_hex()}) - return _dict + return {k: v.as_hex() for k, v in self.__dict__.items()} - class Credit(HyperglassModel): - """Validation model for params.branding.credit.""" + class Fonts(HyperglassModel): + """Validation model for theme fonts.""" - enable: StrictBool = True - - class Font(HyperglassModel): - """Validation model for params.branding.font.""" - - class Primary(HyperglassModel): - """Validation model for params.branding.font.primary.""" - - name: StrictStr = "Nunito" - size: StrictStr = "1rem" - - class Mono(HyperglassModel): - """Validation model for params.branding.font.mono.""" - - name: StrictStr = "Fira Code" - size: StrictStr = "87.5%" - - primary: Primary = Primary() - mono: Mono = Mono() - - class HelpMenu(HyperglassModel): - """Validation model for params.branding.help_menu.""" - - enable: StrictBool = True - file: Optional[FilePath] - title: StrictStr = "Help" - - class Logo(HyperglassModel): - """Validation model for params.branding.logo.""" - - light: Optional[FilePath] - dark: Optional[FilePath] - width: StrictInt = 384 - height: Optional[StrictInt] - favicons: StrictStr = "ui/images/favicons/" - - @validator("favicons") - def favicons_trailing_slash(cls, value): - """If the favicons path does not end in a '/', append it.""" - chars = list(value) - if chars[len(chars) - 1] != "/": - chars.append("/") - return "".join(chars) - - @root_validator(pre=True) - def validate_logo_model(cls, values): - """Set default opengraph image location. - - Arguments: - values {dict} -- Unvalidated model - - Returns: - {dict} -- Modified model - """ - logo_light = values.get("light") - logo_dark = values.get("dark") - default_logo_light = ( - Path(__file__).parent.parent.parent - / "static/images/hyperglass-light.png" - ) - default_logo_dark = ( - Path(__file__).parent.parent.parent - / "static/images/hyperglass-dark.png" - ) - - # Use light logo as dark logo if dark logo is undefined. - if logo_light is not None and logo_dark is None: - values["dark"] = logo_light - - # Use dark logo as light logo if light logo is undefined. - if logo_dark is not None and logo_light is None: - values["light"] = logo_dark - - # Set default logo paths if logo is undefined. - if logo_light is None and logo_dark is None: - values["light"] = default_logo_light - values["dark"] = default_logo_dark - - return values - - @validator("light", "dark") - def validate_logos(cls, value): - """Convert file path to URL path. - - Arguments: - value {FilePath} -- Path to logo file. - - Returns: - {str} -- Formatted logo path - """ - return "".join(str(value).split("static")[1::]) - - class Config: - """Override pydantic config.""" - - fields = {"logo_path": "path"} - - class ExternalLink(HyperglassModel): - """Validation model for params.branding.external_link.""" - - enable: StrictBool = True - title: StrictStr = "PeeringDB" - url: HttpUrl = "https://www.peeringdb.com/AS{primary_asn}" - - class Terms(HyperglassModel): - """Validation model for params.branding.terms.""" - - enable: StrictBool = True - file: Optional[FilePath] - title: StrictStr = "Terms" - - class Text(HyperglassModel): - """Validation model for params.branding.text.""" - - title_mode: constr(regex=("logo_only|text_only|logo_title|all")) = "logo_only" - title: StrictStr = "hyperglass" - subtitle: StrictStr = "AS{primary_asn}" - query_location: StrictStr = "Location" - query_type: StrictStr = "Query Type" - query_target: StrictStr = "Target" - query_vrf: StrictStr = "Routing Table" - terms: StrictStr = "Terms" - info: StrictStr = "Help" - peeringdb = "PeeringDB" - fqdn_tooltip: StrictStr = "Use {protocol}" - cache: StrictStr = "Results will be cached for {timeout} {period}." - - class Error404(HyperglassModel): - """Validation model for 404 Error Page.""" - - title: StrictStr = "Error" - subtitle: StrictStr = "{uri} isn't a thing" - button: StrictStr = "Home" - - class Error500(HyperglassModel): - """Validation model for 500 Error Page.""" - - title: StrictStr = "Error" - subtitle: StrictStr = "Something Went Wrong" - button: StrictStr = "Home" - - error404: Error404 = Error404() - error500: Error500 = Error500() + body: StrictStr = "Nunito" + mono: StrictStr = "Fira Code" colors: Colors = Colors() + fonts: Fonts = Fonts() + + +class Web(HyperglassModel): + """Validation model for all web/browser-related configuration.""" + credit: Credit = Credit() external_link: ExternalLink = ExternalLink() font: Font = Font() @@ -221,3 +262,4 @@ class Web(HyperglassModel): opengraph: OpenGraph = OpenGraph() terms: Terms = Terms() text: Text = Text() + theme: Theme = Theme() diff --git a/hyperglass/constants.py b/hyperglass/constants.py index e0ba92f..ac1d18a 100644 --- a/hyperglass/constants.py +++ b/hyperglass/constants.py @@ -168,6 +168,15 @@ SUPPORTED_QUERY_TYPES = ( "traceroute", ) +FUNC_COLOR_MAP = { + "primary": "cyan", + "secondary": "blue", + "success": "green", + "warning": "yellow", + "error": "orange", + "danger": "red", +} + class Supported: """Define items supported by hyperglass. diff --git a/ui/components/Footer.js b/ui/components/Footer.js index 4e5397d..3b6adda 100644 --- a/ui/components/Footer.js +++ b/ui/components/Footer.js @@ -22,9 +22,9 @@ const Footer = () => { const [helpVisible, showHelp] = useState(false); const [termsVisible, showTerms] = useState(false); const [creditVisible, showCredit] = useState(false); - const extUrl = config.external_link.url.includes("{primary_asn}") - ? config.external_link.url.format({ primary_asn: config.primary_asn }) - : config.external_link.url || "/"; + const extUrl = config.web.external_link.url.includes("{primary_asn}") + ? config.web.external_link.url.format({ primary_asn: config.primary_asn }) + : config.web.external_link.url || "/"; const handleCollapse = i => { if (i === "help") { showTerms(false); @@ -42,31 +42,31 @@ const Footer = () => { }; return ( <> - {config.help.enable && ( + {config.web.help_menu.enable && ( )} - {config.terms.enable && ( + {config.web.terms.enable && ( )} - {config.credit.enable && ( + {config.web.credit.enable && ( { color={footerColor[colorMode]} justifyContent="space-between" > - {config.terms.enable && ( + {config.web.terms.enable && ( handleCollapse("terms")}> - {config.terms.title} + {config.web.terms.title} )} - {config.help.enable && ( + {config.web.help_menu.enable && ( handleCollapse("help")}> - {config.help.title} + {config.web.help_menu.title} )} { marginRight="auto" p={0} /> - {config.credit.enable && ( + {config.web.credit.enable && ( handleCollapse("credit")}> )} - {config.external_link.enable && ( + {config.web.external_link.enable && ( { rightIcon={GoLinkExternal} size="xs" > - {config.external_link.title} + {config.web.external_link.title} )} diff --git a/ui/components/HyperglassForm.js b/ui/components/HyperglassForm.js index 3aa1827..5a93192 100644 --- a/ui/components/HyperglassForm.js +++ b/ui/components/HyperglassForm.js @@ -133,7 +133,7 @@ const HyperglassForm = React.forwardRef( vrfContent && } > - + diff --git a/ui/components/HyperglassProvider.js b/ui/components/HyperglassProvider.js index 825fd9b..67d0cab 100644 --- a/ui/components/HyperglassProvider.js +++ b/ui/components/HyperglassProvider.js @@ -14,7 +14,7 @@ const HyperglassContext = createContext(null); export const HyperglassProvider = ({ config, children }) => { const value = useMemo(() => config, [config]); - const userTheme = value && makeTheme(value.web); + const userTheme = value && makeTheme(value.web.theme); const theme = value ? userTheme : defaultTheme; return ( diff --git a/ui/theme.js b/ui/theme.js index f5454c8..8dd4961 100644 --- a/ui/theme.js +++ b/ui/theme.js @@ -35,6 +35,8 @@ const alphaColors = color => ({ }); const generateColors = colorInput => { + const colorMap = {}; + const lightnessMap = [0.95, 0.85, 0.75, 0.65, 0.55, 0.45, 0.35, 0.25, 0.15, 0.05]; const saturationMap = [0.32, 0.16, 0.08, 0.04, 0, 0, 0.04, 0.08, 0.16, 0.32]; @@ -59,7 +61,6 @@ const generateColors = colorInput => { const getColorNumber = index => (index === 0 ? 50 : index * 100); - const colorMap = {}; colors.map((color, i) => { const colorIndex = getColorNumber(i); colorMap[colorIndex] = color.hex(); @@ -67,61 +68,62 @@ const generateColors = colorInput => { return colorMap; }; -const defaultBasePalette = { - black: "#262626", - white: "#f7f7f7", - gray: "#c1c7cc", - red: "#d84b4b", - orange: "ff6b35", - yellow: "#edae49", - green: "#35b246", - blue: "#314cb6", - teal: "#35b299", - cyan: "#118ab2", - pink: "#f2607d", - purple: "#8d30b5" -}; +// const defaultBasePalette = { +// black: "#262626", +// white: "#f7f7f7", +// gray: "#c1c7cc", +// red: "#d84b4b", +// orange: "ff6b35", +// yellow: "#edae49", +// green: "#35b246", +// blue: "#314cb6", +// teal: "#35b299", +// cyan: "#118ab2", +// pink: "#f2607d", +// purple: "#8d30b5" +// }; -const defaultSwatchPalette = { - black: defaultBasePalette.black, - white: defaultBasePalette.white, - gray: generateColors(defaultBasePalette.gray), - red: generateColors(defaultBasePalette.red), - orange: generateColors(defaultBasePalette.orange), - yellow: generateColors(defaultBasePalette.yellow), - green: generateColors(defaultBasePalette.green), - blue: generateColors(defaultBasePalette.blue), - teal: generateColors(defaultBasePalette.teal), - cyan: generateColors(defaultBasePalette.cyan), - pink: generateColors(defaultBasePalette.pink), - purple: generateColors(defaultBasePalette.purple) -}; -const defaultAlphaPalette = { - blackAlpha: alphaColors(defaultBasePalette.black), - whiteAlpha: alphaColors(defaultBasePalette.white) -}; +// const defaultSwatchPalette = { +// black: defaultBasePalette.black, +// white: defaultBasePalette.white, +// gray: generateColors(defaultBasePalette.gray), +// red: generateColors(defaultBasePalette.red), +// orange: generateColors(defaultBasePalette.orange), +// yellow: generateColors(defaultBasePalette.yellow), +// green: generateColors(defaultBasePalette.green), +// blue: generateColors(defaultBasePalette.blue), +// teal: generateColors(defaultBasePalette.teal), +// cyan: generateColors(defaultBasePalette.cyan), +// pink: generateColors(defaultBasePalette.pink), +// purple: generateColors(defaultBasePalette.purple) +// }; -const defaultFuncSwatchPalette = { - primary: generateColors(defaultBasePalette.cyan), - secondary: generateColors(defaultBasePalette.blue), - dark: generateColors(defaultBasePalette.black), - light: generateColors(defaultBasePalette.white), - success: generateColors(defaultBasePalette.green), - warning: generateColors(defaultBasePalette.yellow), - error: generateColors(defaultBasePalette.orange), - danger: generateColors(defaultBasePalette.red) -}; +// const defaultAlphaPalette = { +// blackAlpha: alphaColors(defaultBasePalette.black), +// whiteAlpha: alphaColors(defaultBasePalette.white) +// }; -const defaultColors = { - transparent: "transparent", - current: "currentColor", - ...defaultFuncSwatchPalette, - ...defaultAlphaPalette, - ...defaultSwatchPalette -}; +// const defaultFuncSwatchPalette = { +// primary: generateColors(defaultBasePalette.cyan), +// secondary: generateColors(defaultBasePalette.blue), +// dark: generateColors(defaultBasePalette.black), +// light: generateColors(defaultBasePalette.white), +// success: generateColors(defaultBasePalette.green), +// warning: generateColors(defaultBasePalette.yellow), +// error: generateColors(defaultBasePalette.orange), +// danger: generateColors(defaultBasePalette.red) +// }; + +// const defaultColors = { +// transparent: "transparent", +// current: "currentColor", +// ...defaultFuncSwatchPalette, +// ...defaultAlphaPalette, +// ...defaultSwatchPalette +// }; const defaultBodyFonts = [ - "Nunito", + // "Nunito", "-apple-system", "BlinkMacSystemFont", '"Segoe UI"', @@ -134,7 +136,7 @@ const defaultBodyFonts = [ ]; const defaultMonoFonts = [ - '"Fira Code"', + // '"Fira Code"', "SFMono-Regular", "Melno", "Monaco", @@ -144,53 +146,63 @@ const defaultMonoFonts = [ "monospace" ]; -const defaultFonts = { - body: defaultBodyFonts.join(", "), - heading: defaultBodyFonts.join(", "), - mono: defaultMonoFonts.join(", ") +// const defaultFonts = { +// body: defaultBodyFonts.join(", "), +// heading: defaultBodyFonts.join(", "), +// mono: defaultMonoFonts.join(", ") +// }; + +// const defaultTheme = { +// ...chakraTheme, +// colors: defaultColors, +// fonts: defaultFonts +// }; + +const generatePalette = palette => { + const generatedPalette = {}; + Object.keys(palette).map(color => { + if (!["black", "white"].includes(color)) { + generatedPalette[color] = generateColors(palette[color]); + } else { + generatedPalette[color] = palette[color]; + generatedPalette[`${color}Alpha`] = alphaColors(palette[color]); + } + }); + return generatedPalette; }; -const defaultTheme = { - ...chakraTheme, - colors: defaultColors, - fonts: defaultFonts +// const generateFuncPalette = palette => ({ +// primary: generateColors(palette.cyan), +// secondary: generateColors(palette.blue), +// dark: generateColors(palette.black), +// light: generateColors(palette.white), +// success: generateColors(palette.green), +// warning: generateColors(palette.yellow), +// error: generateColors(palette.orange), +// danger: generateColors(palette.red) +// }); + +// const generateAlphaPalette = palette => ({ +// blackAlpha: alphaColors(palette.black), +// whiteAlpha: alphaColors(palette.white) +// }); + +const formatFont = font => { + const fontList = font.split(" "); + const fontFmt = fontList.length >= 2 ? `'${fontList.join(" ")}'` : fontList.join(" "); + return fontFmt; }; -const generatePalette = palette => ({ - black: palette.black, - white: palette.white, - gray: generateColors(palette.gray), - red: generateColors(palette.red), - orange: generateColors(palette.orange), - yellow: generateColors(palette.yellow), - green: generateColors(palette.green), - blue: generateColors(palette.blue), - teal: generateColors(palette.teal), - cyan: generateColors(palette.cyan), - pink: generateColors(palette.pink), - purple: generateColors(palette.purple) -}); - -const generateFuncPalette = palette => ({ - primary: generateColors(palette.cyan), - secondary: generateColors(palette.blue), - dark: generateColors(palette.black), - light: generateColors(palette.white), - success: generateColors(palette.green), - warning: generateColors(palette.yellow), - error: generateColors(palette.orange), - danger: generateColors(palette.red) -}); - -const generateAlphaPalette = palette => ({ - blackAlpha: alphaColors(palette.black), - whiteAlpha: alphaColors(palette.white) -}); - const importFonts = userFonts => { const [body, mono] = [defaultBodyFonts, defaultMonoFonts]; - userFonts.primary.name && body.unshift(`'${userFonts.primary.name}'`); - userFonts.mono.name && mono.unshift(`'${userFonts.mono.name}'`); + const bodyFmt = formatFont(userFonts.body); + const monoFmt = formatFont(userFonts.mono); + if (userFonts.body && !body.includes(bodyFmt)) { + body.unshift(bodyFmt); + } + if (userFonts.mono && !mono.includes(monoFmt)) { + mono.unshift(monoFmt); + } return { body: body.join(", "), heading: body.join(", "), @@ -199,26 +211,29 @@ const importFonts = userFonts => { }; const importColors = (userColors = {}) => { - const baseColors = { - ...defaultBasePalette, - ...userColors - }; - const swatchColors = generatePalette(baseColors); - const funcColors = generateFuncPalette(baseColors); - const bwAlphaColors = generateAlphaPalette(baseColors); + // const baseColors = { + // ...defaultBasePalette, + // ...userColors + // }; + + const generatedColors = generatePalette(userColors); + // const swatchColors = generatePalette(baseColors); + // const funcColors = generateFuncPalette(baseColors); + // const bwAlphaColors = generateAlphaPalette(userColors); return { transparent: "transparent", current: "currentColor", - ...swatchColors, - ...funcColors, - ...bwAlphaColors + // ...swatchColors, + // ...funcColors, + ...generatedColors + // ...bwAlphaColors }; }; -const makeTheme = branding => ({ +const makeTheme = userTheme => ({ ...chakraTheme, - colors: importColors(branding.colors), - fonts: importFonts(branding.font) + colors: importColors(userTheme.colors), + fonts: importFonts(userTheme.fonts) }); -export { makeTheme, defaultTheme }; +export { makeTheme, chakraTheme as defaultTheme };