UNPKG

@helpwave/hightide

Version:

helpwave's component and theming library

1,366 lines (1,332 loc) 204 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { ASTNodeInterpreter: () => ASTNodeInterpreter, AnimatedRing: () => AnimatedRing, ArrayUtil: () => ArrayUtil, Avatar: () => Avatar, AvatarGroup: () => AvatarGroup, BreadCrumb: () => BreadCrumb, ButtonSizePaddings: () => ButtonSizePaddings, Carousel: () => Carousel, Checkbox: () => ControlledCheckbox, CheckboxProperty: () => CheckboxProperty, Chip: () => Chip, ChipList: () => ChipList, Circle: () => Circle, ConfirmDialog: () => ConfirmDialog, ControlledDatePicker: () => ControlledDatePicker, ControlledTimePicker: () => ControlledTimePicker, ControlledYearMonthPicker: () => ControlledYearMonthPicker, DEFAULT_LANGUAGE: () => DEFAULT_LANGUAGE, DatePicker: () => DatePicker, DateProperty: () => DateProperty, DateTimePicker: () => DateTimePicker, DayPicker: () => DayPicker, DayPickerControlled: () => DayPickerControlled, DiscardChangesDialog: () => DiscardChangesDialog, DividerInserter: () => DividerInserter, EaseFunctions: () => EaseFunctions, ErrorComponent: () => ErrorComponent, Expandable: () => Expandable, FAQSection: () => FAQSection, FormInput: () => FormInput, Helpwave: () => Helpwave, HelpwaveBadge: () => HelpwaveBadge, HideableContentSection: () => HideableContentSection, Input: () => ControlledInput, InputGroup: () => InputGroup, InputModal: () => InputModal, Label: () => Label, LanguageContext: () => LanguageContext, LanguageModal: () => LanguageModal, LoadingAndErrorComponent: () => LoadingAndErrorComponent, LoadingAnimation: () => LoadingAnimation, LoadingButton: () => LoadingButton, LocalStorageService: () => LocalStorageService, LoopingArrayCalculator: () => LoopingArrayCalculator, MarkdownInterpreter: () => MarkdownInterpreter, Menu: () => Menu2, MenuItem: () => MenuItem, Modal: () => Modal, ModalContext: () => ModalContext, ModalHeader: () => ModalHeader, ModalRegister: () => ModalRegister, MultiSearchWithMapping: () => MultiSearchWithMapping, MultiSelect: () => MultiSelect, MultiSelectProperty: () => MultiSelectProperty, MultiSubjectSearchWithMapping: () => MultiSubjectSearchWithMapping, NumberProperty: () => NumberProperty, OutlineButton: () => OutlineButton, Pagination: () => Pagination, Profile: () => Profile, ProgressIndicator: () => ProgressIndicator, PropertyBase: () => PropertyBase, ProvideLanguage: () => ProvideLanguage, RadialRings: () => RadialRings, Ring: () => Ring, RingWave: () => RingWave, ScrollPicker: () => ScrollPicker, SearchableList: () => SearchableList, SearchableSelect: () => SearchableSelect, Select: () => Select, SessionStorageService: () => SessionStorageService, SimpleSearch: () => SimpleSearch, SimpleSearchWithMapping: () => SimpleSearchWithMapping, SingleSelectProperty: () => SingleSelectProperty, SolidButton: () => SolidButton, SortButton: () => SortButton, StepperBar: () => StepperBar, Table: () => Table, TagIcon: () => TagIcon, TechRadar: () => TechRadar, TextButton: () => TextButton, TextImage: () => TextImage, TextProperty: () => TextProperty, Textarea: () => Textarea, ThemeContext: () => ThemeContext, ThemeProvider: () => ThemeProvider, Tile: () => Tile, TileWithImage: () => TileWithImage, TimeDisplay: () => TimeDisplay, TimePicker: () => TimePicker, ToggleableInput: () => ToggleableInput, ToggleableInputUncontrolled: () => ToggleableInputUncontrolled, Tooltip: () => Tooltip, UncontrolledCheckbox: () => UncontrolledCheckbox, UncontrolledInput: () => UncontrolledInput, VerticalDivider: () => VerticalDivider, YearMonthPicker: () => YearMonthPicker, addDuration: () => addDuration, addElementToTable: () => addElementToTable, avatarSizeMapping: () => avatarSizeMapping, avtarSizeList: () => avtarSizeList, builder: () => builder, changeDuration: () => changeDuration, changeTableSelectionSingle: () => changeTableSelectionSingle, clamp: () => clamp, closestMatch: () => closestMatch, createLoopingList: () => createLoopingList, createLoopingListWithIndex: () => createLoopingListWithIndex, defaultTableStatePagination: () => defaultTableStatePagination, defaultTableStateSelection: () => defaultTableStateSelection, defaultThemeTypeTranslation: () => defaultThemeTypeTranslation, equalDate: () => equalDate, equalSizeGroups: () => equalSizeGroups, filterNews: () => filterNews, formatDate: () => formatDate, formatDateTime: () => formatDateTime, generateShadingColors: () => generateShadingColors, getBetweenDuration: () => getBetweenDuration, getDaysInMonth: () => getDaysInMonth, getNeighbours: () => getNeighbours, getWeeksForCalenderMonth: () => getWeeksForCalenderMonth, isDataObjectSelected: () => isDataObjectSelected, isInTimeSpan: () => isInTimeSpan, languages: () => languages, languagesLocalNames: () => languagesLocalNames, localizedNewsSchema: () => localizedNewsSchema, modalRootName: () => modalRootName, monthsList: () => monthsList, newsListSchema: () => newsListSchema, newsSchema: () => newsSchema, noop: () => noop, pageForItem: () => pageForItem, range: () => range, removeFromTableSelection: () => removeFromTableSelection, shadingColorValues: () => shadingColorValues, subtractDuration: () => subtractDuration, updatePagination: () => updatePagination, useHoverState: () => useHoverState, useLanguage: () => useLanguage, useLocalStorage: () => useLocalStorage, useLocale: () => useLocale, useOutsideClick: () => useOutsideClick, useSaveDelay: () => useSaveDelay, useTheme: () => useTheme, useTranslation: () => useTranslation, validateEmail: () => validateEmail, weekDayList: () => weekDayList }); module.exports = __toCommonJS(index_exports); // src/coloring/shading.ts var import_tinycolor2 = __toESM(require("tinycolor2")); // src/coloring/types.ts var shadingColorValues = [0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1e3]; // src/coloring/shading.ts var generateShadingColors = (partialShading) => { const shading = { 0: "#FFFFFF", 1e3: "#000000" }; let index = 1; while (index < shadingColorValues.length - 1) { const previous = shadingColorValues[index - 1]; const current = shadingColorValues[index]; if (partialShading[current] !== void 0) { shading[current] = partialShading[current]; index++; continue; } let j = index + 1; while (j < shadingColorValues.length) { if (partialShading[shadingColorValues[j]] !== void 0) { break; } j++; } if (j === shadingColorValues.length) { j = shadingColorValues.length - 1; } const nextFound = shadingColorValues[j]; const interval = nextFound - previous; for (let k = index; k < j; k++) { const current2 = shadingColorValues[k]; const previousValue = partialShading[previous] ?? shading[previous]; const nextValue = partialShading[nextFound] ?? shading[nextFound]; shading[current2] = import_tinycolor2.default.mix((0, import_tinycolor2.default)(previousValue), (0, import_tinycolor2.default)(nextValue), (current2 - previous) / interval * 100).toHexString(); } index = j; } return shading; }; // src/components/Avatar.tsx var import_image = __toESM(require("next/image")); var import_clsx = __toESM(require("clsx")); var import_jsx_runtime = require("react/jsx-runtime"); var avtarSizeList = ["tiny", "small", "medium", "large"]; var avatarSizeMapping = { tiny: 24, small: 32, medium: 48, large: 64 }; var Avatar = ({ avatarUrl, alt, size = "medium", className = "" }) => { avatarUrl = "https://cdn.helpwave.de/boringavatar.svg"; const avtarSize = { tiny: 24, small: 32, medium: 48, large: 64 }[size]; const style = { width: avtarSize + "px", height: avtarSize + "px", maxWidth: avtarSize + "px", maxHeight: avtarSize + "px", minWidth: avtarSize + "px", minHeight: avtarSize + "px" }; return ( // TODO transparent or white background later /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.default)(`rounded-full bg-primary`, className), style, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_image.default, { className: "rounded-full border border-gray-200", style, src: avatarUrl, alt, width: avtarSize, height: avtarSize } ) }) ); }; // src/components/AvatarGroup.tsx var import_jsx_runtime2 = require("react/jsx-runtime"); var AvatarGroup = ({ avatars, maxShownProfiles = 5, size = "tiny" }) => { const displayedProfiles = avatars.length < maxShownProfiles ? avatars : avatars.slice(0, maxShownProfiles); const diameter = avatarSizeMapping[size]; const stackingOverlap = 0.5; const notDisplayedProfiles = avatars.length - maxShownProfiles; const avatarGroupWidth = diameter * (stackingOverlap * (displayedProfiles.length - 1) + 1); return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "row relative", style: { height: diameter + "px" }, children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: avatarGroupWidth + "px" }, children: displayedProfiles.map((avatar, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "div", { className: "absolute", style: { left: index * diameter * stackingOverlap + "px", zIndex: maxShownProfiles - index }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { avatarUrl: avatar.avatarUrl, alt: avatar.alt, size }) }, index )) }), notDisplayedProfiles > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "div", { className: "truncate row items-center", style: { fontSize: diameter / 2 + "px", marginLeft: 1 + diameter / 16 + "px" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [ "+ ", notDisplayedProfiles ] }) } ) ] }); }; // src/components/BreadCrumb.tsx var import_link = __toESM(require("next/link")); var import_clsx2 = __toESM(require("clsx")); var import_jsx_runtime3 = require("react/jsx-runtime"); var BreadCrumb = ({ crumbs, linkClassName, containerClassName }) => { const color = "text-description"; return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: (0, import_clsx2.default)("row", containerClassName), children: crumbs.map((crumb, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link.default, { href: crumb.link, className: (0, import_clsx2.default)(linkClassName, { [`${color} hover:brightness-60`]: index !== crumbs.length - 1 }), children: crumb.display }), index !== crumbs.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: (0, import_clsx2.default)(`px-1`, color), children: "/" }) ] }, index)) }); }; // src/components/Button.tsx var import_clsx3 = __toESM(require("clsx")); var import_jsx_runtime4 = require("react/jsx-runtime"); var ButtonSizePaddings = { small: "btn-sm", medium: "btn-md", large: "btn-lg" }; var SolidButton = ({ children, disabled = false, color = "primary", size = "medium", startIcon, endIcon, onClick, className, ...restProps }) => { const colorClasses = { primary: "bg-button-solid-primary-background text-button-solid-primary-text", secondary: "bg-button-solid-secondary-background text-button-solid-secondary-text", tertiary: "bg-button-solid-tertiary-background text-button-solid-tertiary-text", positive: "bg-button-solid-positive-background text-button-solid-positive-text", warning: "bg-button-solid-warning-background text-button-solid-warning-text", negative: "bg-button-solid-negative-background text-button-solid-negative-text" }[color]; const iconColorClasses = { primary: "text-button-solid-primary-icon", secondary: "text-button-solid-secondary-icon", tertiary: "text-button-solid-tertiary-icon", positive: "text-button-solid-positive-icon", warning: "text-button-solid-warning-icon", negative: "text-button-solid-negative-icon" }[color]; return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( "button", { onClick: disabled ? void 0 : onClick, disabled: disabled || onClick === void 0, className: (0, import_clsx3.default)( className, { "text-disabled-text bg-disabled-background": disabled, [(0, import_clsx3.default)(colorClasses, "hover:brightness-90")]: !disabled }, ButtonSizePaddings[size] ), ...restProps, children: [ startIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "span", { className: (0, import_clsx3.default)({ [iconColorClasses]: !disabled, [`text-disabled-icon`]: disabled }), children: startIcon } ), children, endIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "span", { className: (0, import_clsx3.default)({ [iconColorClasses]: !disabled, [`text-disabled-icon`]: disabled }), children: endIcon } ) ] } ); }; var OutlineButton = ({ children, disabled = false, color = "primary", size = "medium", startIcon, endIcon, onClick, className, ...restProps }) => { const colorClasses = { primary: "bg-transparent border-2 border-button-outline-primary-text text-button-outline-primary-text" }[color]; const iconColorClasses = { primary: "text-button-outline-primary-icon" }[color]; return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( "button", { onClick: disabled ? void 0 : onClick, disabled: disabled || onClick === void 0, className: (0, import_clsx3.default)( className, { "text-disabled-text border-disabled-outline)": disabled, [(0, import_clsx3.default)(colorClasses, "hover:brightness-80")]: !disabled }, ButtonSizePaddings[size] ), ...restProps, children: [ startIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "span", { className: (0, import_clsx3.default)({ [iconColorClasses]: !disabled, [`text-disabled-icon`]: disabled }), children: startIcon } ), children, endIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "span", { className: (0, import_clsx3.default)({ [iconColorClasses]: !disabled, [`text-disabled-icon`]: disabled }), children: endIcon } ) ] } ); }; var TextButton = ({ children, disabled = false, color = "neutral", size = "medium", startIcon, endIcon, onClick, className, ...restProps }) => { const colorClasses = { negative: "bg-transparent text-button-text-negative-text", neutral: "bg-transparent text-button-text-neutral-text" }[color]; const iconColorClasses = { negative: "text-button-text-negative-icon", neutral: "text-button-text-neutral-icon" }[color]; return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( "button", { onClick: disabled ? void 0 : onClick, disabled: disabled || onClick === void 0, className: (0, import_clsx3.default)( className, { "text-disabled-text": disabled, [(0, import_clsx3.default)(colorClasses, "hover:bg-button-text-hover-background rounded-full")]: !disabled }, ButtonSizePaddings[size] ), ...restProps, children: [ startIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "span", { className: (0, import_clsx3.default)({ [iconColorClasses]: !disabled, [`text-disabled-icon`]: disabled }), children: startIcon } ), children, endIcon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "span", { className: (0, import_clsx3.default)({ [iconColorClasses]: !disabled, [`text-disabled-icon`]: disabled }), children: endIcon } ) ] } ); }; // src/components/ChipList.tsx var import_clsx4 = __toESM(require("clsx")); var import_jsx_runtime5 = require("react/jsx-runtime"); var Chip = ({ children, trailingIcon, color = "default", variant = "normal", className = "", ...restProps }) => { const colorMapping = { default: "text-tag-default-text bg-tag-default-background", dark: "text-tag-dark-text bg-tag-dark-background", red: "text-tag-red-text bg-tag-red-background", yellow: "text-tag-yellow-text bg-tag-yellow-background", green: "text-tag-green-text bg-tag-green-background", blue: "text-tag-blue-text bg-tag-blue-background", pink: "text-tag-pink-text bg-tag-pink-background" }[color]; const colorMappingIcon = { default: "text-tag-default-icon", dark: "text-tag-dark-icon", red: "text-tag-red-icon", yellow: "text-tag-yellow-icon", green: "text-tag-green-icon", blue: "text-tag-blue-icon", pink: "text-tag-pink-icon" }[color]; return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)( "div", { ...restProps, className: (0, import_clsx4.default)( `row w-fit px-2 py-1`, colorMapping, { "rounded-md": variant === "normal", "rounded-full": variant === "fullyRounded" }, className ), children: [ children, trailingIcon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: colorMappingIcon, children: trailingIcon }) ] } ); }; var ChipList = ({ list, className = "" }) => { return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: (0, import_clsx4.default)("flex flex-wrap gap-x-4 gap-y-2", className), children: list.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( Chip, { ...value, color: value.color ?? "dark", variant: value.variant ?? "normal", children: value.children }, index )) }); }; // src/components/Circle.tsx var import_clsx5 = __toESM(require("clsx")); var import_jsx_runtime6 = require("react/jsx-runtime"); var Circle = ({ radius = 20, className = "bg-primary", style, ...restProps }) => { const size = radius * 2; return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "div", { className: (0, import_clsx5.default)(`rounded-full`, className), style: { width: `${size}px`, height: `${size}px`, ...style }, ...restProps } ); }; // src/components/ErrorComponent.tsx var import_lucide_react = require("lucide-react"); // src/hooks/useLanguage.tsx var import_react2 = require("react"); // src/hooks/useLocalStorage.tsx var import_react = require("react"); // src/util/storage.ts var StorageService = class { // this seems to be a bug in eslint as 'paramter-properties' is a special syntax of typescript constructor(storage) { this.storage = storage; } get(key) { const value = this.storage.getItem(key); if (value === null) { return null; } return JSON.parse(value); } set(key, value) { this.storage.setItem(key, JSON.stringify(value)); } delete(key) { this.storage.removeItem(key); } deleteAll() { this.storage.clear(); } }; var LocalStorageService = class extends StorageService { constructor() { super(window.localStorage); } }; var SessionStorageService = class extends StorageService { constructor() { super(window.sessionStorage); } }; // src/hooks/useLocalStorage.tsx var useLocalStorage = (key, initValue) => { const get = (0, import_react.useCallback)(() => { if (typeof window === "undefined") { return initValue; } const storageService = new LocalStorageService(); const value = storageService.get(key); return value || initValue; }, [initValue, key]); const [storedValue, setStoredValue] = (0, import_react.useState)(get); const setValue = (0, import_react.useCallback)((value) => { const newValue = value instanceof Function ? value(storedValue) : value; const storageService = new LocalStorageService(); storageService.set(key, value); setStoredValue(newValue); }, [storedValue, setStoredValue, key]); (0, import_react.useEffect)(() => { setStoredValue(get()); }, []); return [storedValue, setValue]; }; // src/hooks/useLanguage.tsx var import_jsx_runtime7 = require("react/jsx-runtime"); var languages = ["en", "de"]; var languagesLocalNames = { en: "English", de: "Deutsch" }; var DEFAULT_LANGUAGE = "en"; var LanguageContext = (0, import_react2.createContext)({ language: DEFAULT_LANGUAGE, setLanguage: (v) => v }); var useLanguage = () => (0, import_react2.useContext)(LanguageContext); var useLocale = (overWriteLanguage) => { const { language } = useLanguage(); const mapping = { en: "en-US", de: "de-DE" }; return mapping[overWriteLanguage ?? language]; }; var ProvideLanguage = ({ initialLanguage, children }) => { const [language, setLanguage] = (0, import_react2.useState)(initialLanguage ?? DEFAULT_LANGUAGE); const [storedLanguage, setStoredLanguage] = useLocalStorage("language", initialLanguage ?? DEFAULT_LANGUAGE); (0, import_react2.useEffect)(() => { if (language !== initialLanguage && initialLanguage) { console.warn("LanguageProvider initial state changed: Prefer using useLanguages's setLanguage instead"); setLanguage(initialLanguage); } }, [initialLanguage]); (0, import_react2.useEffect)(() => { setStoredLanguage(language); }, [language, setStoredLanguage]); (0, import_react2.useEffect)(() => { if (storedLanguage !== null) { setLanguage(storedLanguage); return; } const languagesToTestAgainst = Object.values(languages); const matchingBrowserLanguages = window.navigator.languages.map((language2) => languagesToTestAgainst.find((test) => language2 === test || language2.split("-")[0] === test)).filter((entry) => entry !== void 0); if (matchingBrowserLanguages.length === 0) return; const firstMatch = matchingBrowserLanguages[0]; setLanguage(firstMatch); }, []); return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LanguageContext.Provider, { value: { language, setLanguage }, children }); }; // src/hooks/useTranslation.ts var useTranslation = (defaults, translationOverwrite = {}) => { const { language: languageProp, translation: overwrite } = translationOverwrite; const { language: inferredLanguage } = useLanguage(); const usedLanguage = languageProp ?? inferredLanguage; let defaultValues = defaults[usedLanguage]; if (overwrite && overwrite[usedLanguage]) { defaultValues = { ...defaultValues, ...overwrite[usedLanguage] }; } return defaultValues; }; // src/components/ErrorComponent.tsx var import_clsx6 = __toESM(require("clsx")); var import_jsx_runtime8 = require("react/jsx-runtime"); var defaultErrorComponentTranslation = { en: { errorOccurred: "An error occurred" }, de: { errorOccurred: "Ein Fehler ist aufgetreten" } }; var ErrorComponent = ({ overwriteTranslation, errorText, classname }) => { const translation = useTranslation(defaultErrorComponentTranslation, overwriteTranslation); return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: (0, import_clsx6.default)("col items-center justify-center gap-y-4 w-full h-24", classname), children: [ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react.AlertOctagon, { size: 64, className: "text-warning" }), errorText ?? `${translation.errorOccurred} :(` ] }); }; // src/components/Expandable.tsx var import_react3 = require("react"); var import_lucide_react2 = require("lucide-react"); var import_clsx7 = __toESM(require("clsx")); var import_jsx_runtime9 = require("react/jsx-runtime"); var DefaultIcon = (expanded) => expanded ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.ChevronUp, { size: 16, className: "min-w-[16px]" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.ChevronDown, { size: 16, className: "min-w-[16px]" }); var Expandable = (0, import_react3.forwardRef)(({ children, label, icon, initialExpansion = false, clickOnlyOnHeader = true, className = "", headerClassName = "" }, ref) => { const [isExpanded, setIsExpanded] = (0, import_react3.useState)(initialExpansion); icon ??= DefaultIcon; return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)( "div", { ref, className: (0, import_clsx7.default)("col bg-surface text-on-surface group rounded-lg shadow-sm", { "cursor-pointer": !clickOnlyOnHeader }, className), onClick: () => !clickOnlyOnHeader && setIsExpanded(!isExpanded), children: [ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)( "button", { className: (0, import_clsx7.default)("btn-md rounded-lg justify-between items-center bg-surface text-on-surface", { "group-hover:brightness-95": !isExpanded }, headerClassName), onClick: () => clickOnlyOnHeader && setIsExpanded(!isExpanded), children: [ label, icon(isExpanded) ] } ), isExpanded && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "col", children }) ] } ); }); Expandable.displayName = "Expandable"; // src/components/HelpwaveBadge.tsx var import_clsx10 = __toESM(require("clsx")); // src/components/icons/Helpwave.tsx var import_clsx8 = require("clsx"); var import_jsx_runtime10 = require("react/jsx-runtime"); var Helpwave = ({ color = "currentColor", animate = "none", size = 64, ...props }) => { const isLoadingAnimation = animate === "loading"; let svgAnimationKey = ""; if (animate === "pulse") { svgAnimationKey = "animate-pulse"; } else if (animate === "bounce") { svgAnimationKey = "animate-bounce"; } if (size < 0) { console.error("size cannot be less than 0"); size = 64; } return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)( "svg", { width: size, height: size, viewBox: "0 0 888 888", fill: "none", strokeLinecap: "round", strokeWidth: 48, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("g", { className: (0, import_clsx8.clsx)(svgAnimationKey), children: [ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { className: (0, import_clsx8.clsx)({ "animate-wave-big-left-up": isLoadingAnimation }), d: "M144 543.235C144 423.259 232.164 326 340.92 326", stroke: color, strokeDasharray: "1000" }), /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { className: (0, import_clsx8.clsx)({ "animate-wave-big-right-down": isLoadingAnimation }), d: "M537.84 544.104C429.084 544.104 340.92 446.844 340.92 326.869", stroke: color, strokeDasharray: "1000" }), /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { className: (0, import_clsx8.clsx)({ "animate-wave-small-left-up": isLoadingAnimation }), d: "M462.223 518.035C462.223 432.133 525.348 362.495 603.217 362.495", stroke: color, strokeDasharray: "1000" }), /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { className: (0, import_clsx8.clsx)({ "animate-wave-small-right-down": isLoadingAnimation }), d: "M745.001 519.773C666.696 519.773 603.218 450.136 603.218 364.233", stroke: color, strokeDasharray: "1000" }) ] }) } ); }; // src/components/layout/Tile.tsx var import_image2 = __toESM(require("next/image")); var import_clsx9 = __toESM(require("clsx")); var import_jsx_runtime11 = require("react/jsx-runtime"); var Tile = ({ title, description, prefix, suffix, className }) => { return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: (0, import_clsx9.default)("row gap-x-4 w-full items-center", className), children: [ prefix, /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "col w-full", children: [ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: (0, import_clsx9.default)(title.className), children: title.value }), !!description && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: (0, import_clsx9.default)(description.className ?? "textstyle-description"), children: description.value }) ] }), suffix ] }); }; var TileWithImage = ({ url, imageLocation = "prefix", imageSize = { width: 24, height: 24 }, imageClassName = "", ...tileProps }) => { const image = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_image2.default, { src: url, alt: "", ...imageSize, className: (0, import_clsx9.default)(imageClassName) }); return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)( Tile, { ...tileProps, prefix: imageLocation === "prefix" ? image : void 0, suffix: imageLocation === "suffix" ? image : void 0 } ); }; // src/components/HelpwaveBadge.tsx var import_jsx_runtime12 = require("react/jsx-runtime"); var HelpwaveBadge = ({ size = "small", title = "helpwave", className = "" }) => { const iconSize = size === "small" ? 24 : 64; return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)( Tile, { prefix: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Helpwave, { size: iconSize }), title: { value: title, className: size === "small" ? "textstyle-title-lg text-base" : "textstyle-title-xl" }, className: (0, import_clsx10.default)( { "px-2 py-1 rounded-md": size === "small", "px-4 py-1 rounded-md": size === "large" }, className ) } ); }; // src/components/HideableContentSection.tsx var import_react4 = require("react"); var import_lucide_react3 = require("lucide-react"); var import_clsx11 = __toESM(require("clsx")); var import_jsx_runtime13 = require("react/jsx-runtime"); var HideableContentSection = ({ initiallyOpen = true, disabled, children, header }) => { const [open, setOpen] = (0, import_react4.useState)(initiallyOpen); return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "col", children: [ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)( "div", { className: (0, import_clsx11.default)("row justify-between items-center", { "cursor-pointer": !disabled }), onClick: () => { if (!disabled) { setOpen(!open); } }, children: [ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { children: header }), !disabled && (open ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.ChevronUp, {}) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.ChevronDown, {})) ] } ), open && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { children }) ] }); }; // src/components/InputGroup.tsx var import_react5 = require("react"); var import_lucide_react4 = require("lucide-react"); var import_clsx12 = __toESM(require("clsx")); // src/util/noop.ts var noop = () => void 0; // src/components/InputGroup.tsx var import_jsx_runtime14 = require("react/jsx-runtime"); var InputGroup = ({ children, title, expanded = true, isExpandable = true, disabled = false, onChange = noop, className = "" }) => { const [isExpanded, setIsExpanded] = (0, import_react5.useState)(expanded); (0, import_react5.useEffect)(() => { setIsExpanded(expanded); }, [expanded]); return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: (0, import_clsx12.default)("col gap-y-4 p-4 bg-white rounded-xl", className), children: [ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)( "div", { className: (0, import_clsx12.default)( "row justify-between items-center", { "cursor-pointer": isExpandable && !disabled, "cursor-not-allowed": disabled }, { "text-primary": !disabled, "text-primary/40": disabled } ), onClick: () => { if (!isExpandable) { return; } const updatedIsExpanded = !isExpanded; onChange(updatedIsExpanded); setIsExpanded(updatedIsExpanded); }, children: [ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "textstyle-title-md", children: title }), /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: (0, import_clsx12.default)("rounded-full text-white w-6 h-6", { "bg-primary": isExpandable && !disabled || expanded, "bg-primary/40": disabled }), children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.ChevronUp, { className: "-translate-y-[1px]", size: 24 }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.ChevronDown, { className: "translate-y-[1px]", size: 24 }) }) ] } ), isExpanded && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "col gap-y-2 h-full", children }) ] }); }; // src/components/LoadingAndErrorComponent.tsx var import_react6 = require("react"); // src/components/LoadingAnimation.tsx var import_clsx13 = __toESM(require("clsx")); var import_jsx_runtime15 = require("react/jsx-runtime"); var defaultLoadingAnimationTranslation = { en: { loading: "Loading data" }, de: { loading: "Lade Daten" } }; var LoadingAnimation = ({ overwriteTranslation, loadingText, classname }) => { const translation = useTranslation(defaultLoadingAnimationTranslation, overwriteTranslation); return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: (0, import_clsx13.default)("col items-center justify-center w-full h-24", classname), children: [ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Helpwave, { animate: "loading" }), loadingText ?? `${translation.loading}...` ] }); }; // src/components/LoadingAndErrorComponent.tsx var import_jsx_runtime16 = require("react/jsx-runtime"); var LoadingAndErrorComponent = ({ children, isLoading = false, hasError = false, errorProps, loadingProps, minimumLoadingDuration }) => { const [isInMinimumLoading, setIsInMinimumLoading] = (0, import_react6.useState)(false); const [hasUsedMinimumLoading, setHasUsedMinimumLoading] = (0, import_react6.useState)(false); if (minimumLoadingDuration && !isInMinimumLoading && !hasUsedMinimumLoading) { setIsInMinimumLoading(true); setTimeout(() => { setIsInMinimumLoading(false); setHasUsedMinimumLoading(true); }, minimumLoadingDuration); } if (isLoading || minimumLoadingDuration && isInMinimumLoading) { return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LoadingAnimation, { ...loadingProps }); } if (hasError) { return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ErrorComponent, { ...errorProps }); } return children; }; // src/components/LoadingButton.tsx var import_clsx14 = __toESM(require("clsx")); var import_jsx_runtime17 = require("react/jsx-runtime"); var LoadingButton = ({ isLoading = false, size = "medium", onClick, ...rest }) => { const paddingClass = ButtonSizePaddings[size]; return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "inline-block relative", children: [ isLoading && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: (0, import_clsx14.default)("absolute inset-0 row items-center justify-center bg-white/40", paddingClass), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Helpwave, { animate: "loading", className: "text-white" }) }), /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SolidButton, { ...rest, disabled: rest.disabled, onClick: isLoading ? noop : onClick }) ] }); }; // src/components/MarkdownInterpreter.tsx var import_jsx_runtime18 = require("react/jsx-runtime"); var astNodeInserterType = ["helpwave", "newline"]; var ASTNodeInterpreter = ({ node, isRoot = false, className = "" }) => { switch (node.type) { case "newline": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("br", {}); case "text": return isRoot ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className, children: node.text }) : node.text; case "helpwave": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-bold font-space no-underline", children: "helpwave" }); case "none": return isRoot ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className, children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ASTNodeInterpreter, { node: value }, index)) }); case "bold": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("b", { children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ASTNodeInterpreter, { node: value }, index)) }); case "italic": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("i", { children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ASTNodeInterpreter, { node: value }, index)) }); case "underline": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("u", { children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ASTNodeInterpreter, { node: value }, index)) }); case "font-space": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-space", children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }); case "primary": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-primary", children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }); case "secondary": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-secondary", children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }); case "warn": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-warning", children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }); case "positive": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-positive", children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }); case "negative": return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-negative", children: node.children.map((value, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)( ASTNodeInterpreter, { node: value }, index )) }); default: return null; } }; var modifierIdentifierMapping = [ { id: "i", name: "italic" }, { id: "b", name: "bold" }, { id: "u", name: "underline" }, { id: "space", name: "font-space" }, { id: "primary", name: "primary" }, { id: "secondary", name: "secondary" }, { id: "warn", name: "warn" }, { id: "positive", name: "positive" }, { id: "negative", name: "negative" } ]; var inserterIdentifierMapping = [ { id: "helpwave", name: "helpwave" }, { id: "newline", name: "newline" } ]; var parseMarkdown = (text, commandStart = "\\", open = "{", close = "}") => { let start = text.indexOf(commandStart); const children = []; while (text !== "") { if (start === -1) { children.push({ type: "text", text }); break; } children.push(parseMarkdown(text.substring(0, start))); text = text.substring(start); if (text.length <= 1) { children.push({ type: "text", text }); text = ""; continue; } const simpleReplace = [commandStart, open, close]; if (simpleReplace.some((value) => text[1] === value)) { children.push({ type: "text", text: simpleReplace.find((value) => text[1] === value) }); text = text.substring(2); start = text.indexOf(commandStart); continue; } const inserter = inserterIdentifierMapping.find((value) => text.substring(1).startsWith(value.id)); if (inserter) { children.push({ type: inserter.name }); text = text.substring(inserter.id.length + 1); start = text.indexOf(commandStart); continue; } const modifier = modifierIdentifierMapping.find((value) => text.substring(1).startsWith(value.id)); if (modifier) { if (text[modifier.id.length + 1] !== open) { children.push({ type: "text", text: text.substring(0, modifier.id.length + 1) }); text = text.substring(modifier.id.length + 2); start = text.indexOf(commandStart); continue; } let closing = -1; let index = modifier.id.length + 2; let counter = 1; let escaping = false; while (index < text.length) { if (text[index] === open && !escaping) { counter++; } if (text[index] === close && !escaping) { counter--; if (counter === 0) { closing = index; break; } } escaping = text[index] === commandStart; index++; } if (closing !== -1) { children.push({ type: modifier.name, children: [parseMarkdown(text.substring(modifier.id.length + 2, closing))] }); text = text.substring(closing + 1); start = text.indexOf(commandStart); continue; } } children.push({ type: "text", text: text[0] }); text = text.substring(1); start = text.indexOf(commandStart); } return { type: "none", children }; }; var optimizeTree = (node) => { if (node.type === "text") { return !node.text ? void 0 : node; } if (astNodeInserterType.some((value) => value === node.type)) { return node; } const currentNode = node; if (currentNode.children.length === 0) { return void 0; } let children = []; for (let i = 0; i < currentNode.children.length; i++) { const child = optimizeTree(currentNode.children[i]); if (!child) { continue; } if (child.type === "none") { children.push(...child.children); } else { children.push(child); } } currentNode.children = children; children = []; for (let i = 0; i < currentNode.children.length; i++) { const child = currentNode.children[i]; if (child) { if (child.type === "text" && children[children.length - 1]?.type === "text") { children[children.length - 1].text += child.text; } else { children.push(child); } } } currentNode.children = children; return currentNode; }; var MarkdownInterpreter = ({ text, className }) => { const tree = parseMarkdown(text); const optimizedTree = optimizeTree(tree); return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ASTNodeInterpreter, { node: optimizedTree, isRoot: true, className }); }; // src/components/Pagination.tsx var import_lucide_react5 = require("lucide-react"); var import_clsx15 = __toESM(require("clsx")); var import_jsx_runtime19 = require("react/jsx-runtime"); var defaultPaginationTranslations = { en: { of: "of" }, de: { of: "von" } }; var Pagination = ({ overwriteTranslation, page, numberOfPages, onPageChanged }) => { const translation = useTranslation(defaultPaginationTranslations, overwriteTranslation); const changePage = (page2) => { onPageChanged(page2); }; const noPages = numberOfPages === 0; const onFirstPage = page === 0 && !noPages; const onLastPage = page === numberOfPages - 1; return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: (0, import_clsx15.default)("row", { "opacity-30": noPages }), children: [ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => changePage(0), disabled: onFirstPage, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.ChevronFirst, { className: (0, import_clsx15.default)({ "opacity-30": onFirstPage }) }) }), /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => changePage(page - 1), disabled: onFirstPage, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.ChevronLeft, { className: (0, import_clsx15.default)({ "opacity-30": onFirstPage }) }) }), /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "min-w-[80px] justify-center mx-2", children: [ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "select-none text-right flex-1", children: noPages ? 0 : page + 1 }), /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "select-none mx-2", children: translation.of }), /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "select-none text-left flex-1", children: numberOfPages }) ] }), /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => changePage(page + 1), disabled: onLastPage || noPages, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.ChevronRight, { className: (0, import_clsx15.default)({ "opacity-30": onLastPage }) }) }), /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => changePage(numberOfPages - 1), disabled: onLastPage || noPages, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.ChevronLast, { className: (0, import_clsx15.default)({ "opacity-30": onLastPage }) }) }) ] }); }; // src/components/Profile.tsx var import_clsx16 = __toESM(require("clsx")); var import_image3 = __toESM(require("next/image")); var import_link2 = __toESM(require("next/link")); var import_lucide_react6 = require("lucide-react"); var import_jsx_runtime20 = require("react/jsx-runtime"); var SocialIcon = ({ type, url, size = 24 }) => { let icon; switch (type) { case "mail": icon = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Mail, { size }); break; case "linkedin": icon = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Linkedin, { size }); break; case "github": icon = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Github, { size }); break; case "website": icon = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Globe, { size }); break; case "medium": icon = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Globe, { size }); break; default: icon = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Helpwave, { size: 24 }); } return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_link2.default, { href: url, target: "_blank", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Chip, { color: "dark", className: "!p-2", children: icon }) }); }; var Profile = ({ name, imageUrl, badge, prefix, suffix, roleBadge, role, tags, info, socials, className, imageClassName, ...divProps }) => { return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)( "div", { ...divProps, className: (0, import_clsx16.default)(`col items-center text-center rounded-3xl p-3 pb-4 bg-white text-gray