discord-card-react
Version:
React Discord profile card component
1 lines • 225 kB
Source Map (JSON)
{"version":3,"file":"index.umd.mjs","sources":["../node_modules/react/cjs/react-jsx-runtime.production.js","../node_modules/react/cjs/react-jsx-runtime.development.js","../node_modules/react/jsx-runtime.js","../src/components/sections/badge.tsx","../src/components/base-discord-card.tsx","../src/components/sections/basic-info.tsx","../src/components/sections/status.tsx","../src/components/section-title.tsx","../src/components/sections/about-me.tsx","../src/components/sections/member-since.tsx","../src/components/Role.tsx","../src/components/sections/role.tsx","../src/hooks/useAutosizeTextArea.ts","../src/components/sections/note.tsx","../src/components/sections/message.tsx","../src/helpers/helper-functions.ts","../src/components/seek-bar.tsx","../src/components/spotify-logo.tsx","../src/components/sections/spotify.tsx","../src/components/sections/activity.tsx","../src/components/Separator.tsx","../src/components/discord-card.tsx","../node_modules/tslib/tslib.es6.mjs","../node_modules/react-use-lanyard/dist/constants.js","../node_modules/react-use-lanyard/dist/kv.js","../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js","../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js","../node_modules/use-sync-external-store/shim/index.js","../node_modules/swr/dist/_internal/events.js","../node_modules/dequal/lite/index.js","../node_modules/swr/dist/_internal/config-context-client-BKoingCI.js","../node_modules/swr/dist/_internal/constants.js","../node_modules/swr/dist/_internal/index.js","../node_modules/swr/dist/index/index.js","../node_modules/react-use-lanyard/dist/lanyard.js","../node_modules/react-use-lanyard/dist/types.js","../node_modules/react-use-lanyard/dist/index.js","../src/components/lanyard-discord-card.tsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\");\nfunction jsxProd(type, config, maybeKey) {\n var key = null;\n void 0 !== maybeKey && (key = \"\" + maybeKey);\n void 0 !== config.key && (key = \"\" + config.key);\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n config = maybeKey.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== config ? config : null,\n props: maybeKey\n };\n}\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsxProd;\nexports.jsxs = jsxProd;\n","/**\n * @license React\n * react-jsx-runtime.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function getComponentNameFromType(type) {\n if (null == type) return null;\n if (\"function\" === typeof type)\n return type.$$typeof === REACT_CLIENT_REFERENCE\n ? null\n : type.displayName || type.name || null;\n if (\"string\" === typeof type) return type;\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return \"Fragment\";\n case REACT_PROFILER_TYPE:\n return \"Profiler\";\n case REACT_STRICT_MODE_TYPE:\n return \"StrictMode\";\n case REACT_SUSPENSE_TYPE:\n return \"Suspense\";\n case REACT_SUSPENSE_LIST_TYPE:\n return \"SuspenseList\";\n case REACT_ACTIVITY_TYPE:\n return \"Activity\";\n }\n if (\"object\" === typeof type)\n switch (\n (\"number\" === typeof type.tag &&\n console.error(\n \"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.\"\n ),\n type.$$typeof)\n ) {\n case REACT_PORTAL_TYPE:\n return \"Portal\";\n case REACT_CONTEXT_TYPE:\n return type.displayName || \"Context\";\n case REACT_CONSUMER_TYPE:\n return (type._context.displayName || \"Context\") + \".Consumer\";\n case REACT_FORWARD_REF_TYPE:\n var innerType = type.render;\n type = type.displayName;\n type ||\n ((type = innerType.displayName || innerType.name || \"\"),\n (type = \"\" !== type ? \"ForwardRef(\" + type + \")\" : \"ForwardRef\"));\n return type;\n case REACT_MEMO_TYPE:\n return (\n (innerType = type.displayName || null),\n null !== innerType\n ? innerType\n : getComponentNameFromType(type.type) || \"Memo\"\n );\n case REACT_LAZY_TYPE:\n innerType = type._payload;\n type = type._init;\n try {\n return getComponentNameFromType(type(innerType));\n } catch (x) {}\n }\n return null;\n }\n function testStringCoercion(value) {\n return \"\" + value;\n }\n function checkKeyStringCoercion(value) {\n try {\n testStringCoercion(value);\n var JSCompiler_inline_result = !1;\n } catch (e) {\n JSCompiler_inline_result = !0;\n }\n if (JSCompiler_inline_result) {\n JSCompiler_inline_result = console;\n var JSCompiler_temp_const = JSCompiler_inline_result.error;\n var JSCompiler_inline_result$jscomp$0 =\n (\"function\" === typeof Symbol &&\n Symbol.toStringTag &&\n value[Symbol.toStringTag]) ||\n value.constructor.name ||\n \"Object\";\n JSCompiler_temp_const.call(\n JSCompiler_inline_result,\n \"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.\",\n JSCompiler_inline_result$jscomp$0\n );\n return testStringCoercion(value);\n }\n }\n function getTaskName(type) {\n if (type === REACT_FRAGMENT_TYPE) return \"<>\";\n if (\n \"object\" === typeof type &&\n null !== type &&\n type.$$typeof === REACT_LAZY_TYPE\n )\n return \"<...>\";\n try {\n var name = getComponentNameFromType(type);\n return name ? \"<\" + name + \">\" : \"<...>\";\n } catch (x) {\n return \"<...>\";\n }\n }\n function getOwner() {\n var dispatcher = ReactSharedInternals.A;\n return null === dispatcher ? null : dispatcher.getOwner();\n }\n function UnknownOwner() {\n return Error(\"react-stack-top-frame\");\n }\n function hasValidKey(config) {\n if (hasOwnProperty.call(config, \"key\")) {\n var getter = Object.getOwnPropertyDescriptor(config, \"key\").get;\n if (getter && getter.isReactWarning) return !1;\n }\n return void 0 !== config.key;\n }\n function defineKeyPropWarningGetter(props, displayName) {\n function warnAboutAccessingKey() {\n specialPropKeyWarningShown ||\n ((specialPropKeyWarningShown = !0),\n console.error(\n \"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)\",\n displayName\n ));\n }\n warnAboutAccessingKey.isReactWarning = !0;\n Object.defineProperty(props, \"key\", {\n get: warnAboutAccessingKey,\n configurable: !0\n });\n }\n function elementRefGetterWithDeprecationWarning() {\n var componentName = getComponentNameFromType(this.type);\n didWarnAboutElementRef[componentName] ||\n ((didWarnAboutElementRef[componentName] = !0),\n console.error(\n \"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.\"\n ));\n componentName = this.props.ref;\n return void 0 !== componentName ? componentName : null;\n }\n function ReactElement(type, key, props, owner, debugStack, debugTask) {\n var refProp = props.ref;\n type = {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n props: props,\n _owner: owner\n };\n null !== (void 0 !== refProp ? refProp : null)\n ? Object.defineProperty(type, \"ref\", {\n enumerable: !1,\n get: elementRefGetterWithDeprecationWarning\n })\n : Object.defineProperty(type, \"ref\", { enumerable: !1, value: null });\n type._store = {};\n Object.defineProperty(type._store, \"validated\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: 0\n });\n Object.defineProperty(type, \"_debugInfo\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: null\n });\n Object.defineProperty(type, \"_debugStack\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugStack\n });\n Object.defineProperty(type, \"_debugTask\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugTask\n });\n Object.freeze && (Object.freeze(type.props), Object.freeze(type));\n return type;\n }\n function jsxDEVImpl(\n type,\n config,\n maybeKey,\n isStaticChildren,\n debugStack,\n debugTask\n ) {\n var children = config.children;\n if (void 0 !== children)\n if (isStaticChildren)\n if (isArrayImpl(children)) {\n for (\n isStaticChildren = 0;\n isStaticChildren < children.length;\n isStaticChildren++\n )\n validateChildKeys(children[isStaticChildren]);\n Object.freeze && Object.freeze(children);\n } else\n console.error(\n \"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.\"\n );\n else validateChildKeys(children);\n if (hasOwnProperty.call(config, \"key\")) {\n children = getComponentNameFromType(type);\n var keys = Object.keys(config).filter(function (k) {\n return \"key\" !== k;\n });\n isStaticChildren =\n 0 < keys.length\n ? \"{key: someKey, \" + keys.join(\": ..., \") + \": ...}\"\n : \"{key: someKey}\";\n didWarnAboutKeySpread[children + isStaticChildren] ||\n ((keys =\n 0 < keys.length ? \"{\" + keys.join(\": ..., \") + \": ...}\" : \"{}\"),\n console.error(\n 'A props object containing a \"key\" prop is being spread into JSX:\\n let props = %s;\\n <%s {...props} />\\nReact keys must be passed directly to JSX without using spread:\\n let props = %s;\\n <%s key={someKey} {...props} />',\n isStaticChildren,\n children,\n keys,\n children\n ),\n (didWarnAboutKeySpread[children + isStaticChildren] = !0));\n }\n children = null;\n void 0 !== maybeKey &&\n (checkKeyStringCoercion(maybeKey), (children = \"\" + maybeKey));\n hasValidKey(config) &&\n (checkKeyStringCoercion(config.key), (children = \"\" + config.key));\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n children &&\n defineKeyPropWarningGetter(\n maybeKey,\n \"function\" === typeof type\n ? type.displayName || type.name || \"Unknown\"\n : type\n );\n return ReactElement(\n type,\n children,\n maybeKey,\n getOwner(),\n debugStack,\n debugTask\n );\n }\n function validateChildKeys(node) {\n isValidElement(node)\n ? node._store && (node._store.validated = 1)\n : \"object\" === typeof node &&\n null !== node &&\n node.$$typeof === REACT_LAZY_TYPE &&\n (\"fulfilled\" === node._payload.status\n ? isValidElement(node._payload.value) &&\n node._payload.value._store &&\n (node._payload.value._store.validated = 1)\n : node._store && (node._store.validated = 1));\n }\n function isValidElement(object) {\n return (\n \"object\" === typeof object &&\n null !== object &&\n object.$$typeof === REACT_ELEMENT_TYPE\n );\n }\n var React = require(\"react\"),\n REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\"),\n ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n hasOwnProperty = Object.prototype.hasOwnProperty,\n isArrayImpl = Array.isArray,\n createTask = console.createTask\n ? console.createTask\n : function () {\n return null;\n };\n React = {\n react_stack_bottom_frame: function (callStackForError) {\n return callStackForError();\n }\n };\n var specialPropKeyWarningShown;\n var didWarnAboutElementRef = {};\n var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(\n React,\n UnknownOwner\n )();\n var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));\n var didWarnAboutKeySpread = {};\n exports.Fragment = REACT_FRAGMENT_TYPE;\n exports.jsx = function (type, config, maybeKey) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !1,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n exports.jsxs = function (type, config, maybeKey) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !0,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","import { Badge } from \"../../types\";\nimport styles from \"../../styles/BadgeSection.module.css\";\n\n/**\n * Renders a list of badges in a <ul> container.\n *\n * @param {Badge[]} badges - An array of Badge objects\n * @return {JSX.Element} The list of badges rendered as JSX\n */\nconst BadgeSection = ({ badges }: { badges: Badge[] }) => {\n return (\n <ul className={styles.badgeContainer}>\n {badges.map((badge) => (\n <li key={badge.name}>\n <img\n src={badge.iconUrl}\n className={styles.badgeIcon}\n alt={badge.name}\n />\n </li>\n ))}\n </ul>\n );\n};\n\nexport default BadgeSection;\n","import styles from \"../styles/BaseDiscordCard.module.css\";\nimport preflightStyles from \"../styles/DiscordCardPreflight.module.css\";\nimport BadgeSection from \"./sections/badge\";\nimport { Badge, ConnectionStatus } from \"../types\";\n\nconst BaseDiscordCard = ({\n imageUrl,\n bannerUrl,\n primaryColor,\n accentColor,\n badges,\n connectionStatus = \"online\",\n children,\n}: {\n imageUrl: string;\n bannerUrl: string;\n primaryColor: string;\n accentColor: string;\n badges?: Badge[];\n connectionStatus?: ConnectionStatus;\n children: React.JSX.Element | React.JSX.Element[];\n}) => {\n return (\n <div className={`${styles.container} ${preflightStyles.discordCardScope}`}>\n <div\n className={styles.cardWrapper}\n style={{\n background: `linear-gradient(to bottom, ${primaryColor}, ${accentColor})`,\n }}\n >\n <div className={styles.cardContent}>\n <div className={styles.profileSection}>\n <img\n src={imageUrl}\n alt=\"Discord profile picture\"\n className={styles.profileImage}\n />\n <div\n className={styles.profileBackgroundGradient}\n style={{\n background: `linear-gradient(to bottom, ${primaryColor} 60%, transparent 40%)`,\n }}\n ></div>\n <div\n className={styles.profileShadowOverlay}\n style={{\n background: `linear-gradient(to bottom, #00000099 60%, transparent 40%)`,\n }}\n />\n </div>\n <img src={bannerUrl} className={styles.bannerImage} alt=\"\" />\n <div className={styles.statusIndicator}>\n <img\n src={`${\n connectionStatus === \"offline\"\n ? \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAClUExURQAAAHR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnR/jnWAj254hmVve2BodWZvfE1TXDs+RTM1OzAzOGZwfXR/j3F8i1RbZTY4Pi4wNS8xNjAyN1RbZjY5PzM2O2BpdTEzOP///5shBGgAAAAfdFJOUwAAIGKn1/L9HyOC1voHY9nYEZL5+KIGIoHVYaal8fw1lhpWAAAAAWJLR0Q2R7+I0QAAAAd0SU1FB+gDEAAUItq0iLEAAAEFSURBVCjPhZNrd4IwDIaLVbl5A3Wb21xFKYhAQaf//68tieVM+WDeL03y5OSkbSIEygEN5HA0dt3xaCg99EUndPwgnCirSRj4/wlgTGdz9aSFnFoORxQvVU+rOLpzoOsuuAN19jpCDJVjy1SyPxz2ibIZ8Rtwx5Gru5vqLD8e80wXtr5E7C/QPpVVbUwDMqauyhP19w44oNRStwQpodUlBT8c4W3IqtrmQe2ZghtPSLzTrqjNIzaXAvtbfoovytNPFLim8LcI8UiyPs4SjIdii7XTvOnpN8XqW+Eivt76+HZF/MNhpjjTGnMx5lmYR2W+hPtQZhxeDxMzitwgM2vALdGrFfwD3RBlxXL9e7YAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjQtMDMtMTZUMDA6MjA6MjQrMDA6MDDJWktTAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDI0LTAzLTE2VDAwOjIwOjI0KzAwOjAwuAfz7wAAACh0RVh0ZGF0ZTp0aW1lc3RhbXAAMjAyNC0wMy0xNlQwMDoyMDozNCswMDowMCO40q4AAAAASUVORK5CYII=\"\n : connectionStatus === \"idle\"\n ? \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAADPUExURQAAAPqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGvqmGv///5vYaPcAAABDdFJOUwAABlzO/vLXp2IfAyqa+PrVgiNy9NgHAn79khEPuqJQkROeIoCBeYv5YbOlWyjk1ivxmzXj/CHBNLlPpvd/eIpj2SBnFTDgAAAAAWJLR0RE+bSYwQAAAAd0SU1FB+gDEAAUItq0iLEAAAEjSURBVCjPddNpe4IwDADghiFY3CqgIIdzU3c4nbrD3ffy//+TKXJT8qUPfaENacpYHqAd6dgxzC63gILVAqB3fCIQsW87bvMFOaMNhijD435zAZoZBWHiIoqVG4xP8RCTuMnkZyL1c031+VRPWXDl57OU0Zur+CJjvFTxVc62xerpA1znvLhh9fRAW+aMK3bbqzjAelPwlul3ZaatgkLxnuFDaXnSx12Jn1hHDEZZejQ+v2CFDRwGY8jitaK0uIkYvr1Pk9NcB7uKUmofcvjUZ1/fP8sN1mLF+AJbg8pi2e0si+q0Mx0JuF6bygMF4EKtSTsA+JGaD80EEE9UmrYi1SOOGn9XNDIN/u9fLavSNZAFdZ1tP7PGJZIP/7xrGmFYvYJ7Rhp0DlJ+GwsAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjQtMDMtMTZUMDA6MjA6MjQrMDA6MDDJWktTAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDI0LTAzLTE2VDAwOjIwOjI0KzAwOjAwuAfz7wAAACh0RVh0ZGF0ZTp0aW1lc3RhbXAAMjAyNC0wMy0xNlQwMDoyMDozMyswMDowMOYf7CAAAAAASUVORK5CYII=\"\n : connectionStatus === \"dnd\"\n ? \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAACoUExURQAAAPBHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/BHR/JHR/JHR/NHR/RHR/BHR/JHR/FHR+5HR8pDRII6PW44PNJERE41OSsxNiwxNk81OdNERJw9QC0xNi8xNp0+QP///64uacQAAAAmdFJOUwAAIGKn1/L9HyOC1vr51Qdj2dgGEZP4kqOhkWEigdQeYKXy8P38brNUXgAAAAFiS0dENzC4uEcAAAAHdElNRQfoAxAAFCFDvdkLAAAAxElEQVQoz4WT6Q6CMAyAizCQU1DA+9aCoOKBvv+juUWM0Wz0+7M139JsXQsg0Dgd3WCmZZnM0Lsihg8isB3XwwY/cOzvAb7phRH+0NcHjedLnPj4RzqM357bEUoYx0LzzAlKmfD8XIe+XKdToe0IFbAZ1w4qmWvQcdV6sQTdU2t/BQZm+UFKnuEaWF6URyllkQewOZ2ri5TqetvC7l4/FNTPPaWJ5MTViIcRZSGKSnwJ9aFEO7Q3E9GKVCMTY0ANUdsIvgC0fm1phA7QmwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNC0wMy0xNlQwMDoyMDoyMyswMDowMAz9dd0AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjQtMDMtMTZUMDA6MjA6MjMrMDA6MDB9oM1hAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0LTAzLTE2VDAwOjIwOjMzKzAwOjAw5h/sIAAAAABJRU5ErkJggg==\"\n : \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAA/UExURQAAAEO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gUO1gf///3Uepd8AAAATdFJOUwAAIGKn1/L9I4LW+gdj2RGT+aNu7qdNAAAAAWJLR0QUkt/JNQAAAAd0SU1FB+gDEAAUI62zuCcAAACdSURBVCjPhZNZDsMgDAUd9iVs8f3vWqOmqloF3vyANcgCYxNNDkFpY533zhqtZkwfZhBiynyTUwzfA7I5S+UfajlvL0vrg/8Yvb292IsfuNrUkrnzI13yiy7jWY8ydai8oAbRkZfEg1Ra66RI57XOmgxvMGR32pLbaUd+pz3SIDm4GngYKAsoKvgS9KGgHfbNBFoRNTIYAzREuxF8Af/sNElcLcDyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDI0LTAzLTE2VDAwOjIwOjI1KzAwOjAwby1A5wAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyNC0wMy0xNlQwMDoyMDoyNSswMDowMB5w+FsAAAAodEVYdGRhdGU6dGltZXN0YW1wADIwMjQtMDMtMTZUMDA6MjA6MzQrMDA6MDAjuNKuAAAAAElFTkSuQmCC\"\n }`}\n className={styles.statusIcon}\n alt=\"\"\n aria-label={`This user's status is ${connectionStatus}`}\n />\n </div>\n {badges && <BadgeSection badges={badges} />}\n </div>\n <div className={styles[\"discord-card-outer-body\"]}>\n <div className={styles[\"discord-card-inner-body\"]}>{children}</div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default BaseDiscordCard;\n","import styles from \"../../styles/BasicInfoSection.module.css\";\n\n/**\n * Renders a basic info section with display name, username, and pronouns.\n *\n * @param {{displayname?: string; username?: string; pronouns?: string;}} - Object with optional display name, username, and pronouns\n * @return {JSX.Element} - The rendered basic info section\n */\nconst BasicInfoSection = ({\n displayname,\n username,\n pronouns,\n}: {\n displayname?: string;\n username?: string;\n pronouns?: string;\n}) => {\n return (\n <section className={styles.section}>\n {displayname && <h1 className={styles.displayName}>{displayname}</h1>}\n {username && <h2 className={styles.username}>{username}</h2>}\n {username && <p className={styles.pronouns}>{pronouns}</p>}\n </section>\n );\n};\n\nexport default BasicInfoSection;\n","import styles from \"../../styles/StatusSection.module.css\";\n\n/**\n * Renders a status section component with an optional icon, emoji, and status text.\n *\n * @param {string} iconUrl - The URL for the icon image.\n * @param {string} emoji - The emoji to display.\n * @param {string} status - The status text to display.\n * @return {JSX.Element} The rendered status section component.\n */\nconst StatusSection = ({\n iconUrl,\n emoji,\n status,\n}: {\n iconUrl?: string;\n emoji?: string;\n status: string;\n}) => {\n return (\n <section className={styles.container}>\n {iconUrl && <img src={iconUrl} className={styles.icon} alt=\"\" />}\n {emoji && <p className={styles.emoji}>{emoji}</p>}\n <p className={styles.status}>{status}</p>\n </section>\n );\n};\n\nexport default StatusSection;\n","import styles from \"../styles/SectionTitle.module.css\";\n\nconst SectionTitle = ({\n title,\n marginBottom,\n}: {\n title: string;\n marginBottom?: number;\n}) => {\n return (\n <h3 className={styles.title} style={{ marginBottom: marginBottom }}>\n {title}\n </h3>\n );\n};\n\nexport default SectionTitle;\n","import React from \"react\";\nimport { AboutMeItem } from \"../../types\";\nimport SectionTitle from \"../section-title\";\nimport styles from \"../../styles/AboutMeSection.module.css\";\n\n/**\n * Generates the About Me section with a title and optional items.\n *\n * @param {React.JSX.Element | React.JSX.Element[]} children - The content of the About Me section.\n * @param {string} title - The title of the About Me section.\n * @param {AboutMeItem[]} items - The items to display in the About Me section, instead of passing children to it.\n * @return {JSX.Element} The About Me section component.\n */\nconst AboutMeSection = ({\n children,\n title,\n items,\n}: {\n children?: React.JSX.Element | React.JSX.Element[];\n title?: string;\n items?: AboutMeItem[];\n}) => {\n return (\n <section className={styles.aboutMeSection}>\n <SectionTitle title={title || \"About Me\"} />\n {items &&\n items.map((item, index) =>\n // Convert it into a link if href attribute is provided\n item.href ? (\n <a\n key={index}\n className={styles.aboutMeLink}\n style={{ marginBottom: item.marginBottom }}\n href={item.href}\n target=\"_blank\"\n >\n {item.text}\n </a>\n ) : (\n <p key={index} style={{ marginBottom: item.marginBottom }}>\n {item.text}\n </p>\n )\n )}\n <>{children}</>\n </section>\n );\n};\n\nexport default AboutMeSection;\n","import SectionTitle from \"../section-title\";\nimport styles from \"../../styles/MemberSinceSection.module.css\";\n/**\n * Renders a section displaying the member's join dates on Discord and the server.\n *\n * @param {string} title - Optional title for the section\n * @param {string} discordJoinDate - The date the member joined Discord\n * @param {string} serverJoinDate - Optional date the member joined the server\n * @param {string} serverIconUrl - Optional URL for the server icon\n * @param {string} serverName - Optional name of the server (Used for accessibility in the alt attribute)\n * @return {JSX.Element} The rendered section component\n */\nconst MemberSinceSection = ({\n title,\n discordJoinDate,\n serverJoinDate,\n serverIconUrl,\n serverName,\n}: {\n title?: string;\n discordJoinDate: string;\n serverJoinDate?: string;\n serverIconUrl?: string;\n serverName?: string;\n}) => {\n return (\n <section>\n <SectionTitle title={title || \"Member since\"} marginBottom={3} />\n <div className={styles.container}>\n {serverJoinDate ? (\n <>\n <svg\n className={styles.discordIcon}\n aria-label=\"Discord\"\n aria-hidden=\"false\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"28\"\n height=\"28\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <path\n fill=\"currentColor\"\n d=\"M19.73 4.87a18.2 18.2 0 0 0-4.6-1.44c-.21.4-.4.8-.58 1.21-1.69-.25-3.4-.25-5.1 0-.18-.41-.37-.82-.59-1.2-1.6.27-3.14.75-4.6 1.43A19.04 19.04 0 0 0 .96 17.7a18.43 18.43 0 0 0 5.63 2.87c.46-.62.86-1.28 1.2-1.98-.65-.25-1.29-.55-1.9-.92.17-.12.32-.24.47-.37 3.58 1.7 7.7 1.7 11.28 0l.46.37c-.6.36-1.25.67-1.9.92.35.7.75 1.35 1.2 1.98 2.03-.63 3.94-1.6 5.64-2.87.47-4.87-.78-9.09-3.3-12.83ZM8.3 15.12c-1.1 0-2-1.02-2-2.27 0-1.24.88-2.26 2-2.26s2.02 1.02 2 2.26c0 1.25-.89 2.27-2 2.27Zm7.4 0c-1.1 0-2-1.02-2-2.27 0-1.24.88-2.26 2-2.26s2.02 1.02 2 2.26c0 1.25-.88 2.27-2 2.27Z\"\n ></path>\n </svg>\n <p className={styles.text}>{discordJoinDate}</p>\n <div className={styles.separator}></div>\n {serverIconUrl && (\n <img\n className={styles.serverIcon}\n alt=\"\"\n aria-label={serverName}\n src={serverIconUrl}\n />\n )}\n <p className={styles.text}>{serverJoinDate}</p>\n </>\n ) : (\n <p className={styles.text}>{discordJoinDate}</p>\n )}\n </div>\n </section>\n );\n};\n\nexport default MemberSinceSection;\n","/**\n * Renders a role component with the specified role and color.\n *\n * @param {string} role - The role to be displayed\n * @param {string} color - The color of the role icon\n * @return {JSX.Element} The role component JSX\n */\nimport styles from \"../styles/Role.module.css\";\n\nconst Role = ({ role, color }: { role: string; color: string }) => {\n return (\n <li className={styles.roleContainer}>\n <div className={styles.roleIcon} style={{ backgroundColor: color }}></div>\n <div className={styles.roleText}>{role}</div>\n </li>\n );\n};\n\nexport default Role;\n","import React from \"react\";\nimport { Role as RoleItem } from \"../../types\";\nimport SectionTitle from \"../section-title\";\nimport Role from \"../Role\";\nimport styles from \"../../styles/RoleSection.module.css\";\n\n/**\n * Render a section for displaying roles with an optional alternative title and list of roles.\n *\n * @param {string} title - Optional title for the section\n * @param {React.JSX.Element | React.JSX.Element[]} children - Optional children elements\n * @param {Role[]} roles - List of roles to display\n * @return {React.JSX.Element} The JSX element representing the role section\n */\nconst RoleSection = ({\n title,\n children,\n roles,\n}: {\n title?: string;\n children?: React.JSX.Element | React.JSX.Element[];\n roles?: RoleItem[];\n}) => {\n const childrenCount = React.Children.count(children);\n\n return (\n <section>\n <SectionTitle\n title={title || childrenCount == 1 ? \"Role\" : \"Roles\"}\n marginBottom={8}\n />\n <ul className={styles.rolesList}>\n {roles &&\n roles.map((role, index) => (\n <Role key={index} role={role.name} color={role.color} />\n ))}\n {children}\n </ul>\n </section>\n );\n};\n\nexport default RoleSection;\n","import { useEffect } from \"react\";\n\n// Credit: https://medium.com/@oherterich/creating-a-textarea-with-dynamic-height-using-react-and-typescript-5ed2d78d9848\n\nconst useAutosizeTextArea = (\n textAreaRef: HTMLTextAreaElement | null,\n value: string\n) => {\n useEffect(() => {\n if (textAreaRef) {\n textAreaRef.style.height = \"0px\";\n const scrollHeight = textAreaRef.scrollHeight;\n textAreaRef.style.height = scrollHeight + \"px\";\n }\n }, [textAreaRef, value]);\n};\n\nexport default useAutosizeTextArea;\n","import { useRef } from \"react\";\nimport useAutosizeTextArea from \"../../hooks/useAutosizeTextArea\";\nimport SectionTitle from \"../section-title\";\nimport styles from \"../../styles/NoteSection.module.css\";\n/**\n * Renders a Discord note section with a title, note content, and input field for adding notes.\n *\n * @param {string} title - The title of the note section\n * @param {string} note - The current note content\n * @param {string} placeholder - The placeholder text for the input field\n * @param {function} handleInput - The function to handle input changes\n * @return {JSX.Element} A section component with a title, note input field, and note content\n */\nconst NoteSection = ({\n title,\n note = \"\",\n placeholder,\n handleInput,\n}: {\n title?: string;\n note?: string;\n placeholder?: string;\n handleInput: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n}) => {\n const noteRef = useRef<HTMLTextAreaElement>(null);\n\n useAutosizeTextArea(noteRef.current, note);\n\n return (\n <section>\n {title ? <SectionTitle title={title} /> : <SectionTitle title=\"Note\" />}\n <textarea\n placeholder={placeholder ? placeholder : \"Add a note\"}\n value={note}\n className={styles.noteTextarea}\n onInput={handleInput}\n maxLength={255}\n ref={noteRef}\n rows={1}\n style={{\n padding: \"0.2rem\",\n marginTop: \"0.5rem\",\n resize: \"none\",\n }}\n ></textarea>\n </section>\n );\n};\n\nexport default NoteSection;\n","import { useRef } from \"react\";\nimport useAutosizeTextArea from \"../../hooks/useAutosizeTextArea\";\nimport styles from \"../../styles/MessageSection.module.css\";\n/**\n * Generates a Discord message section with a textarea for input.\n *\n * @param {string} message - The message to display in the textarea\n * @param {string} placeholder - The placeholder text for the textarea\n * @param {string} accentColor - The color to use for the textarea border\n * @param {function} handleInput - The function to handle input changes in the textarea\n * @return {JSX.Element} The JSX element representing the message section\n */\nconst MessageSection = ({\n message = \"\",\n placeholder,\n accentColor,\n handleInput,\n}: {\n message?: string;\n placeholder?: string;\n accentColor?: string;\n handleInput: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n}) => {\n const messageRef = useRef<HTMLTextAreaElement>(null);\n useAutosizeTextArea(messageRef.current, message);\n\n return (\n <section className={styles.section}>\n <textarea\n ref={messageRef}\n placeholder={placeholder ? placeholder : \"Message this user\"}\n value={message}\n onChange={handleInput}\n className={styles.textarea}\n style={{\n border: `0.5px solid ${accentColor ? accentColor : \"#ccc\"}`,\n padding: \"0.75rem\",\n resize: \"none\",\n }}\n />\n </section>\n );\n};\n\nexport default MessageSection;\n","// Formats the time in milliseconds to a string in the format of \"hh:mm:ss\" or \"mm:ss\" if the time is less than an hour.\nexport const formatTime = (startTimeMs: number, endTimeMs: number) => {\n const secondAsMilliseconds = 1000;\n const minuteAsMilliseconds = secondAsMilliseconds * 60;\n const hourAsMilliseconds = minuteAsMilliseconds * 60;\n\n const distance = endTimeMs - startTimeMs;\n const seconds = Math.floor((distance / secondAsMilliseconds) % 60).toString().padStart(2, \"0\");\n let minutes = Math.floor((distance / minuteAsMilliseconds) % 60).toString()\n if (distance < hourAsMilliseconds) return `${minutes}:${seconds}`;\n\n minutes = minutes.padStart(2, \"0\");\n const hours = Math.floor(distance / hourAsMilliseconds).toString()\n return `${hours}:${minutes}:${seconds}`;\n}\n\n","/**\n * Renders the seek bar for the SpotifySection component.\n */\nimport { useEffect, useState } from \"react\";\nimport { formatTime } from \"../helpers/helper-functions\";\nimport styles from \"../styles/SeekBar.module.css\";\n\nconst SeekBar = ({\n startTimeMs,\n endTimeMs,\n}: {\n startTimeMs: number;\n endTimeMs: number;\n}) => {\n const [currentDateTime, setCurrentDateTime] = useState(new Date());\n\n useEffect(() => {\n const interval = setInterval(() => setCurrentDateTime(new Date()), 1000);\n return () => clearInterval(interval);\n }, [startTimeMs]);\n\n const currentPosition = formatTime(startTimeMs, currentDateTime.getTime());\n const songDuration = formatTime(startTimeMs, endTimeMs);\n const percentage =\n ((currentDateTime.getTime() - startTimeMs) / (endTimeMs - startTimeMs)) *\n 100;\n\n return (\n <div className={styles.container}>\n <div className={styles.bar}>\n <div\n className={styles.progress}\n style={{ width: `${percentage}%` }}\n ></div>\n </div>\n <div className={styles.timeContainer}>\n <div className={styles.timeText}>{currentPosition}</div>\n <div className={styles.timeText}>{songDuration}</div>\n </div>\n </div>\n );\n};\n\nexport default SeekBar;\n","export const SpotifyLogo = ({color = \"#00DA5A\", size = 20}:{color?: string, size?: number}) => {\n return (\n <svg\n width={size + \"px\"}\n height={size + \"px\"}\n viewBox=\"0 0 48 48\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g\n id=\"Icons\"\n stroke=\"none\"\n strokeWidth=\"1\"\n fill=\"none\"\n fillRule=\"evenodd\"\n >\n <g\n id=\"Color-\"\n transform=\"translate(-200.000000, -460.000000)\"\n fill={color}\n >\n <path\n d=\"M238.16,481.36 C230.48,476.8 217.64,476.32 210.32,478.6 C209.12,478.96 207.92,478.24 207.56,477.16 C207.2,475.96 207.92,474.76 209,474.4 C217.52,471.88 231.56,472.36 240.44,477.64 C241.52,478.24 241.88,479.68 241.28,480.76 C240.68,481.6 239.24,481.96 238.16,481.36 M237.92,488.08 C237.32,488.92 236.24,489.28 235.4,488.68 C228.92,484.72 219.08,483.52 211.52,485.92 C210.56,486.16 209.48,485.68 209.24,484.72 C209,483.76 209.48,482.68 210.44,482.44 C219.2,479.8 230,481.12 237.44,485.68 C238.16,486.04 238.52,487.24 237.92,488.08 M235.04,494.68 C234.56,495.4 233.72,495.64 233,495.16 C227.36,491.68 220.28,490.96 211.88,492.88 C211.04,493.12 210.32,492.52 210.08,491.8 C209.84,490.96 210.44,490.24 211.16,490 C220.28,487.96 228.2,488.8 234.44,492.64 C235.28,493 235.4,493.96 235.04,494.68 M224,460 C210.8,460 200,470.8 200,484 C200,497.2 210.8,508 224,508 C237.2,508 248,497.2 248,484 C248,470.8 237.32,460 224,460\"\n id=\"Spotify\"\n ></path>\n </g>\n </g>\n </svg>\n )\n }\n \n export default SpotifyLogo","import SectionTitle from \"../section-title\";\nimport SeekBar from \"../seek-bar\";\nimport styles from \"../../styles/SpotifySection.module.css\";\nimport SpotifyLogo from \"../spotify-logo\";\n/**\n * Renders a section displaying Spotify song information.\n *\n * @param {string} title - The title of the section\n * @param {string} song - The name of the song\n * @param {string} artist - The name of the artist\n * @param {string} album - The name of the album\n * @param {string} artUrl - The URL of the album art\n * @param {string} trackUrl - The URL of the track on Spotify\n * @param {number} startTimeMs - The start time of the song in milliseconds\n * @param {number} endTimeMs - The end time of the song in milliseconds\n * @param {string} primaryColor - The color of the button (inherited from card)\n * @param {string} playOnSpotifyText - The text to display on the button (default: Play on Spotify)\n * @param {string} byString - The string to display before the artist's name (default: by)\n * @param {string} onString - The string to display before the album's name (default: on)\n * @return {JSX.Element} The rendered Spotify section\n */\n\nconst SpotifySection = ({\n title,\n song,\n artist,\n album,\n artUrl,\n trackUrl,\n startTimeMs,\n endTimeMs,\n primaryColor,\n playOnSpotifyText,\n byText = \"by\",\n onText = \"on\",\n}: {\n title?: string;\n song: string;\n artist: string;\n album: string;\n artUrl?: string;\n trackUrl?: string;\n startTimeMs?: number;\n endTimeMs?: number;\n primaryColor?: string;\n playOnSpotifyText?: string;\n byText?: string;\n onText?: string;\n}) => {\n return (\n <section>\n <div className={styles.header}>\n <SectionTitle title={title || \"Listening to Spotify\"} />\n <SpotifyLogo />\n </div>\n <div className={styles.content}>\n {artUrl && (\n <div className={styles.albumArtContainer}>\n {trackUrl ? (\n <a href={trackUrl} target=\"_blank\">\n <img src={artUrl} className={styles.albumArt} alt={album} />\n </a>\n ) : (\n <img src={artUrl} className={styles.albumArt} alt={album} />\n )}\n </div>\n )}\n <div>\n <div className={styles.songTitle}>\n {song.length <= 27 ? song : `${song.substring(0, 27)}...`}\n </div>\n <div className={styles.songInfo}>\n {byText}{\" \"}\n {artist.length <= 27 ? artist : `${artist.substring(0, 27)}...`}\n </div>\n <div className={styles.songInfo}>\n {onText}{\" \"}\n {album.length <= 27 ? album : `${album.substring(0, 27)}...`}\n </div>\n </div>\n </div>\n\n {startTimeMs && endTimeMs && (\n <SeekBar startTimeMs={startTimeMs} endTimeMs={endTimeMs} />\n )}\n\n {trackUrl && (\n <div>\n <a\n target=\"_blank\"\n href={trackUrl}\n className={`${styles.playButton} ${styles.lighten}`}\n style={{ backgroundColor: primaryColor }}\n aria-label={`Play ${song} by ${artist} on Spotify`}\n >\n <div className={styles.playButtonContent}>\n <SpotifyLogo color={\"#fff\"} size={16} />\n {playOnSpotifyText || \"Play on Spotify\"}\n </div>\n </a>\n </div>\n )}\n </section>\n );\n};\n\nexport default SpotifySection;\n","import { formatTime } from \"../../helpers/helper-functions\";\nimport { Party } from \"../../types\";\nimport SectionTitle from \"../section-title\";\nimport { useEffect, useState } from \"react\";\nimport styles from \"../../styles/ActivitySection.module.css\";\n\n/**\n * Renders a section for displaying activity information.\n *\n * @param {string} title - The title of the activity\n * @param {string} name - The name of the activity\n * @param {string} state - The state of the activity\n * @param {string} details - Additional details about the activity\n * @param {string} largeImage - URL for the large image related to the activity\n * @param {string} smallImage - URL for the small image related to the activity\n * @param {Party} party - Object containing information about the party related to the activity\n * @param {string} elapsedText - The text to display before the elapsed time (default: elapsed)\n * @param {\"left\" | \"right\"} timeAlignment - The alignment of the elapsed time (default: left)\n * @param {number} startTime - The start time of the activity\n * @param {string} primaryColor - The color of the button (inherited from card)\n * @param {string} buttonText - The text to display on the button (default: null)\n * @return {JSX.Element} The rendered section component\n */\nconst ActivitySection = ({\n title,\n name,\n state,\n details,\n largeImage,\n smallImage,\n party,\n elapsedText = \"elapsed\",\n timeAlignment = \"left\",\n startTime,\n buttonText,\n primaryColor,\n}: {\n title?: string;\n applicationId?: string;\n name?: string;\n state?: string;\n details?: string;\n largeImage?: string;\n smallImage?: string;\n party?: Party;\n elapsedText?: string;\n timeAlignment?: \"left\" | \"right\";\n startTime?: number;\n buttonText?: string;\n primaryColor?: string;\n}) => {\n const [currentDateTime, setCurrentDateTime] = useState(new Date());\n\n // Update to current time every second\n useEffect(() => {\n const interval = setInterval(() => setCurrentDateTime(new Date()), 1000);\n return () => clearInterval(interval);\n }, [startTime]);\n\n const elapsedTime = formatTime(startTime!, currentDateTime.getTime());\n\n return (\n <section>\n <div className={styles.header}>\n <SectionTitle title={title || \"Playing a game\"} />\n </div>\n <div className={styles.content}>\n {largeImage ? (\n <div className={styles.imageContainer}>\n <div className={styles.imageWrapper}>\n <img src={largeImage} alt=\"\" className={styles.largeImage} />\n {smallImage && (\n <img\n src={smallImage}\n alt=\"\"\n className={styles.smallImageOverlay}\n />\n )}\n </div>\n </div>\n ) : (\n <>\n {smallImage && (\n <div className={styles.smallImageContainer}>\n <img\n src={smallImage}\n alt=\"\"\n className={styles.smallImageStandalone}\n />\n </div>\n )}\n </>\n )}\n <div className={styles.textContainer}>\n {name && <div className={styles.activityName}>{name}</div>}\n {details && (\n <div className={styles.activityDetails}>\n {details.length <= 30\n ? details\n : `${details.substring(0, 30)}...`}\n </div>\n )}\n {state && (\n <>\n {party && party.currentSize && party.maxSize ? (\n <div className={styles.activityState}>\n {state.length <= 30\n ? `${state} (${party.currentSize}/${party.maxSize})`\n : `${state.substring(0, 30)}... (${party.currentSize}/${\n party.maxSize\n })`}\n </div>\n ) : (\n <div className={styles.activityState}>\n {state.length <= 30 ? state : `${state.substring(0, 30)}...`}\n </div>\n )}\n </>\n )}\n {startTime && (\n <div className={styles.activityTime}>\n {timeAlignment === \"left\"\n ? `${elapsedTime} ${elapsedText}`\n : `${elapsedText} ${elapsedTime}`}\n </div>\n )}\n </div>\n </div>\n {buttonText && (\n <div className={styles.buttonWrapper}>\n <button\n className={`${styles.button}`}\n style={{ backgroundColor: primaryColor, cursor: \"not-allowed\" }}\n type=\"button\"\n >\n <div style={{ height: 32 }} className={styles.buttonContent}>\n {buttonText}\n </div>\n </button>\n </div>\n )}\n </section>\n );\n};\n\nexport default ActivitySection;\n","import styles from \"../styles/Separator.module.css\";\n\n/**\n * Function that returns a JSX element representing a separator (Discord style).\n *\n * @return {JSX.Element} JSX element representing a separator\n */\nconst Separator = () => {\n return <div className={styles.separator}></div>;\n};\n\nexport default Separator;\n","import React from \"react\";\nimport BaseDiscordCard from \"./base-discord-card\";\nimport BasicInfoSection from \"./sections/basic-info\";\nimport StatusSection from \"./sections/status\";\nimport AboutMeSection from \"./sections/about-me\";\nimport MemberSinceSection from \"./sections/member-since\";\nimport RoleSection from \"./sections/role\";\nimport NoteSection from \"./sections/note\";\nimport MessageSection from \"./sections/message\";\nimport SpotifySection from \"./sections/spotify\";\nimport ActivitySection from \"./sections/activity\";\nimport {\n BasicInfoSectionProps,\n ConnectionStatus,\n Badge,\n StatusSectionProps,\n AboutMeSectionProps,\n MemberSinceSectionProps,\n RoleSectionProps,\n NoteSectionProps,\n MessageSectionProps,\n SpotifySectionProps,\n ActivitySectionProps,\n} from \"../types\";\nimport styles from \"../styles/BaseDiscordCard.module.css\";\nimport Separator from \"./Separator\";\n\nconst DiscordCard = ({\n imageUrl,\n bannerUrl,\n primaryColor,\n accentColor,\n basicInfo,\n connectionStatus = \"online\",\n badges,\n status,\n aboutMe,\n memberSince,\n roles,\n note,\n message,\n spotify,\n activity,\n children,\n}: {\n imageUrl: string;\n bannerUrl: string;\n primaryColor: string;\n accentColor: string;\n basicInfo: BasicInfoSectionProps;\n connectionStatus?: ConnectionStatus;\n badges?: Badge[];\n status?: StatusSectionProps;\n aboutMe?: AboutMeSectionProps;\n memberSince?: MemberSinceSectionProps;\n roles?: RoleSectionProps;\n note?: NoteSectionProps;\n message?: MessageSectionProps;\n spotify?: SpotifySectionProps;\n activity?: ActivitySectionProps;\n children?: React.JSX.Element | React.JSX.Element[];\n}) => {\n return (\n <BaseDiscordCard\n imageUrl={imageUrl}\n bannerUrl={bannerUrl}\n primaryColor={primaryColor}\n accentColor={accentColor}\n badges={badges}\n connectionStatus={connectionStatus}\n >\n <>\n <>\n <BasicInfoSection {...basicInfo} />\n <>{status == null && <Separator />}</>\n </>\n {status && (\n <>\n <StatusSection {...status} />\n <Separator />\n </>\n )}\n <div className={styles.spaceY2}>\n {aboutMe && <AboutMeSection {...aboutMe} />}\n {memberSince && <MemberSinceSection {...memberSince} />}\n {spotify && (\n