Compare commits

...

775 Commits

Author SHA1 Message Date
gitea_admin f722aa4b85 Remove focus outlines from interactive elements 2026-06-23 10:44:03 +02:00
gitea_admin 636f6cf436 Increase form section spacing 2026-06-23 09:20:24 +02:00
gitea_admin 3ac9143d8b Remove extra checkbox invalid body margin 2026-06-22 18:31:26 +02:00
gitea_admin 2cc460c78a Remove checkbox invalid stack gap 2026-06-22 18:28:30 +02:00
gitea_admin e6b76c88ed Tighten checkbox invalid stack spacing 2026-06-22 18:24:17 +02:00
gitea_admin 1f478a8059 Tighten checkbox invalid spacing 2026-06-22 18:21:12 +02:00
gitea_admin a2468ce2f1 Fix public page layout mobile margins 2026-06-22 18:20:59 +02:00
gitea_admin 6fff7e4b50 Align checkbox invalid validation text 2026-06-22 18:19:53 +02:00
gitea_admin a74d00f62c Align radio invalid validation text 2026-06-22 18:16:31 +02:00
gitea_admin 4f79673bd4 Fix radio invalid label alignment 2026-06-22 18:14:58 +02:00
gitea_admin c1165315e6 Commit current styleguide updates 2026-06-22 18:11:38 +02:00
gitea_admin b595347f60 Add invalid states for interactive elements 2026-06-22 18:07:31 +02:00
gitea_admin 6c103d1dfd Increase global heading foundation sizes 2026-06-22 15:26:30 +02:00
gitea_admin 1771cef831 Adjust typography preview heading sizes 2026-06-22 15:25:12 +02:00
gitea_admin 1e16cb81c9 Increase public heading top spacing 2026-06-22 14:34:47 +02:00
gitea_admin 7ae6315543 Restore white intro text 2026-06-22 14:33:10 +02:00
gitea_admin 66d5e8b653 Remove public layout heading card 2026-06-22 14:31:22 +02:00
gitea_admin 6f6dd21c51 Force dark content card text white 2026-06-18 12:35:29 +02:00
gitea_admin eb2624115d Fix dark footer text color 2026-06-18 12:32:23 +02:00
gitea_admin f96b6349d6 Make dark content card text white 2026-06-18 12:30:06 +02:00
gitea_admin c86c52c4f7 Add dark content card variant 2026-06-18 12:27:25 +02:00
gitea_admin 72ab0f5415 Move VSF list detail title above page 2026-06-18 12:18:30 +02:00
gitea_admin 38dcf146af Restore VSF list detail page title 2026-06-18 12:16:51 +02:00
gitea_admin a69b68dc79 Remove legacy VSF list detail layout rules 2026-06-18 12:15:31 +02:00
gitea_admin 053d1e62b0 Reduce mobile content offset in VSF list detail 2026-06-18 12:14:01 +02:00
gitea_admin 210daba064 Adjust mobile panel spacing for VSF list detail 2026-06-18 12:12:32 +02:00
gitea_admin 0441490a53 Tighten mobile tab spacing 2026-06-18 12:09:59 +02:00
gitea_admin 3e05839dc8 Add mobile tab switcher for VSF list detail 2026-06-18 12:07:50 +02:00
gitea_admin f9db8beb2a Remove VSF list detail filters 2026-06-18 12:03:46 +02:00
gitea_admin 441c63d967 Remove VSF list detail page header 2026-06-18 12:01:24 +02:00
gitea_admin 3cb3766a05 Flatten public footer box 2026-06-18 11:52:30 +02:00
gitea_admin 4e24faefeb Use content card for footer 2026-06-18 11:49:34 +02:00
gitea_admin 9ac8569d2e Use two-column footer content 2026-06-18 11:40:57 +02:00
gitea_admin 6c7e9bb635 Add public layout footer card 2026-06-18 11:21:13 +02:00
gitea_admin d7b79e8907 Expand public layout text width 2026-06-18 11:19:40 +02:00
gitea_admin ee8ff56ae3 Remove public filter bar 2026-06-18 11:18:51 +02:00
gitea_admin 18f3a73a28 Use public portal header pattern 2026-06-18 11:17:10 +02:00
gitea_admin 4ca88808c9 Add public content mirror layout 2026-06-18 11:15:04 +02:00
gitea_admin d85b5ff31f Add public page layout variant 2026-06-18 11:09:54 +02:00
gitea_admin 3a596f3308 Align card list heading block with app layout 2026-06-18 10:55:55 +02:00
gitea_admin b89a88a7ef Limit page layout intro text width 2026-06-18 10:54:22 +02:00
gitea_admin e90e521df8 Rename page layout basic to app 2026-06-18 10:47:28 +02:00
gitea_admin fba8781732 Add bottom spacing to page layout heading card 2026-06-18 10:45:33 +02:00
gitea_admin 5e9e5b3592 Add intro text to page layout heading card 2026-06-18 10:44:31 +02:00
gitea_admin e7b3e01124 Add top spacing to page layout heading 2026-06-18 10:43:40 +02:00
gitea_admin f57c77bd32 Wrap page layout H1 in transparent card 2026-06-18 10:40:59 +02:00
gitea_admin fbbb986f6e Adjust page layout heading contrast 2026-06-18 10:39:21 +02:00
gitea_admin a6b154ee94 Add basic page layout demo 2026-06-18 10:37:28 +02:00
gitea_admin 1552cbf042 Add auth segment to public portal header 2026-06-18 10:25:31 +02:00
gitea_admin f4632f6543 Add public portal header pattern 2026-06-18 10:20:27 +02:00
gitea_admin 94a1ac9b33 Add content basic object card variant 2026-06-18 10:04:11 +02:00
gitea_admin bb824cb540 Adjust card list intro spacing 2026-06-17 14:46:19 +02:00
gitea_admin 3c8773ad7b Fix card list page header spacing 2026-06-17 14:32:12 +02:00
gitea_admin 46a742fe1a Fix form sections login field width 2026-06-17 13:44:19 +02:00
gitea_admin 9dfbd7ca5f Fix left navigation content heading overflow 2026-06-16 20:44:59 +02:00
gitea_admin a0777312c2 Stop left navigation card stretching 2026-06-16 20:41:56 +02:00
gitea_admin 8690a64a94 Add demo text to left navigation content 2026-06-16 20:40:48 +02:00
gitea_admin 0204e9ec99 Add content heading to left navigation 2026-06-16 20:38:48 +02:00
gitea_admin 075f8ff5ee Fix left navigation card height 2026-06-16 20:32:44 +02:00
gitea_admin 8a7b6fad29 Align mobile search clear button 2026-06-16 14:22:07 +02:00
gitea_admin 5523c9ed1a Adjust options row search layout 2026-06-16 14:10:41 +02:00
gitea_admin 899af962a6 Keep add-to-list overlay header and footer fixed 2026-06-16 11:00:39 +02:00
gitea_admin 27bb573191 Override overlay host overflow for scrolling 2026-06-16 10:50:48 +02:00
gitea_admin f58c80a333 Measure overlay height from host 2026-06-16 10:48:08 +02:00
gitea_admin 8d3368019c Reserve space for open overlay card 2026-06-16 10:45:14 +02:00
gitea_admin 81e338ea0e Restore overlay stacking behavior 2026-06-16 10:34:26 +02:00
gitea_admin 0058e55867 Keep overlay card in flow for full height 2026-06-16 10:28:50 +02:00
gitea_admin 964142b00a Constrain overlay card to bottom inset 2026-06-16 10:23:27 +02:00
gitea_admin 94751068b7 Limit overlay card to parent height 2026-06-16 10:20:52 +02:00
gitea_admin 67c869b246 Allow overlay card to overflow target 2026-06-16 09:41:09 +02:00
gitea_admin 64e9b4b838 Align overlay validation with input component 2026-06-16 08:43:35 +02:00
gitea_admin b96e178b0a Improve input validation accessibility 2026-06-16 08:42:17 +02:00
gitea_admin 6a3c29b5c3 Show duplicate list name validation 2026-06-16 08:39:41 +02:00
gitea_admin d35afc0228 Move create-list action to save 2026-06-16 07:03:39 +02:00
gitea_admin 359fcd61a0 Make create-list button full width 2026-06-16 07:00:58 +02:00
gitea_admin c1ab1f1e96 Stage overlay card changes until save 2026-06-16 06:59:04 +02:00
gitea_admin 36ae461901 Open add-to-list overlay directly 2026-06-16 06:53:54 +02:00
gitea_admin 8be8c1b313 Fix overlay card click blocking 2026-06-16 06:52:21 +02:00
gitea_admin e26adf4927 Fix add-to-list overlay bottom corners 2026-06-15 17:48:47 +02:00
gitea_admin 9511e98875 Remove Large Table demo interactions 2026-06-15 16:36:30 +02:00
gitea_admin 46e1b5ad5a Clarify Large Table demo search 2026-06-15 16:34:06 +02:00
gitea_admin 1ba5b029bd Adjust left navigation vertical alignment 2026-06-15 15:05:02 +02:00
gitea_admin 2b034373ef Move create-list content into second segment 2026-06-15 13:11:56 +02:00
gitea_admin fbdccb7c01 Fix create-list title spacing conflict 2026-06-15 13:05:30 +02:00
gitea_admin 6ce6609617 Remove duplicated create-list footer spacing 2026-06-15 12:30:14 +02:00
gitea_admin ec33343937 Set create-list footer spacing 2026-06-15 12:00:11 +02:00
gitea_admin 5ee47fb6cf Move create-list spacing to actions block 2026-06-15 11:50:50 +02:00
gitea_admin 32ef3edd7a Restore top spacing for create-list title 2026-06-15 11:49:01 +02:00
gitea_admin 7ce434110b Align create-list title spacing with form sections 2026-06-15 11:41:06 +02:00
gitea_admin 9f233ddb37 Increase create-list title bottom spacing 2026-06-15 11:38:28 +02:00
gitea_admin dc85f18d0c Fix create-list title spacing 2026-06-15 11:37:28 +02:00
gitea_admin 651d671dd9 Adjust create-list title spacing 2026-06-15 11:33:31 +02:00
gitea_admin fab8b2c406 Hide create-list title until form opens 2026-06-15 11:32:17 +02:00
gitea_admin 2ff332b34c Place create-list title above form 2026-06-15 11:30:00 +02:00
gitea_admin e6da8aa4a5 Move create-list title above list 2026-06-15 11:28:45 +02:00
gitea_admin 632f9b23a4 Move create-list title above actions 2026-06-15 11:24:37 +02:00
gitea_admin bb48e82d35 Swap add-to-list action buttons 2026-06-15 11:17:48 +02:00
gitea_admin 3bbf797840 Activate create-list submit on input 2026-06-15 11:15:46 +02:00
gitea_admin 29afac7be4 Hide create-list form wrapper by default 2026-06-15 11:14:11 +02:00
gitea_admin e34285df39 Add create-list form reveal to overlay 2026-06-15 11:09:31 +02:00
gitea_admin 769c832076 Remove fixed overlay height 2026-06-15 11:05:17 +02:00
gitea_admin d9135741e9 Move add-to-list spacing into list block 2026-06-15 11:04:08 +02:00
gitea_admin c04c11d3c1 Add spacing above add-to-list overlay 2026-06-15 11:01:30 +02:00
gitea_admin 97f728ef32 Fix add-to-list overlay list icon styling 2026-06-15 10:51:55 +02:00
gitea_admin abd8864aa9 Implement add-to-list overlay list state 2026-06-15 10:48:46 +02:00
gitea_admin 87425b693d Add add-to-list overlay pattern 2026-06-15 10:39:30 +02:00
gitea_admin e35643c270 Adjust overlay card vertical behavior 2026-06-15 10:35:32 +02:00
gitea_admin 379a3dec24 Add white star to company card header 2026-06-15 10:18:49 +02:00
gitea_admin 8233735fbf Render small sandwich button as star icon 2026-06-15 10:14:57 +02:00
gitea_admin 0f998acb48 Use star icon for small sandwich button 2026-06-15 10:13:00 +02:00
gitea_admin 1412db647b Add company card bookmark icon 2026-06-15 10:06:44 +02:00
gitea_admin 338afe1a26 Rename Company Card layout title 2026-06-15 09:59:53 +02:00
gitea_admin fab999d524 Duplicate gesamtscore chart rows 2026-06-14 15:59:57 +02:00
gitea_admin a95af3e9c4 Revert "Update Gesamtscore chart preview"
This reverts commit 2b503cd3b2.
2026-06-14 15:58:46 +02:00
gitea_admin 0adbd795ce Revert "Restore score bar row layout"
This reverts commit 1f26b43cae.
2026-06-14 15:58:17 +02:00
gitea_admin 1f26b43cae Restore score bar row layout 2026-06-14 15:57:12 +02:00
gitea_admin 2b503cd3b2 Update Gesamtscore chart preview 2026-06-14 15:55:50 +02:00
gitea_admin ea76e923b9 Fix mobile list group card height 2026-06-14 12:06:55 +02:00
gitea_admin b989195cfd Rename object group card variant 2026-06-12 09:02:29 +02:00
gitea_admin 66868c3c80 Add 600px object group card variant 2026-06-12 09:01:25 +02:00
gitea_admin 5b2e0ffc60 Fix object group card width tokens 2026-06-12 08:53:13 +02:00
gitea_admin 74b47c1ccb Cap object group card shared width 2026-06-12 08:52:05 +02:00
gitea_admin e156e99b21 Adjust object group card sizing 2026-06-12 08:50:10 +02:00
gitea_admin 436eb5558a Add keycloak login validation text 2026-06-11 11:19:00 +02:00
gitea_admin 542ed5bb36 Add validation examples for interactive inputs 2026-06-11 11:15:19 +02:00
gitea_admin 350bffd883 Update register link text 2026-06-11 11:09:16 +02:00
gitea_admin 4d0015004c Update account prompt 2026-06-11 11:08:43 +02:00
gitea_admin 155cdce413 Restore social login heading 2026-06-11 11:08:07 +02:00
gitea_admin 04a936b084 Replace social login block with text 2026-06-11 11:06:57 +02:00
gitea_admin f2f63be34a Update social login heading 2026-06-11 11:05:46 +02:00
gitea_admin 5f016f8472 Remove portal header from register layout 2026-06-11 11:04:58 +02:00
gitea_admin b44c1a10a8 Translate sign in form to English 2026-06-11 11:04:34 +02:00
gitea_admin 5607400156 Update blue header title 2026-06-11 11:01:34 +02:00
gitea_admin bdab229ad9 Update form title 2026-06-11 11:01:05 +02:00
gitea_admin 32cc0517ec Remove register layout body segment 2026-06-11 10:59:54 +02:00
gitea_admin d72c706196 Correct register layout header title 2026-06-11 10:59:24 +02:00
gitea_admin 374b264218 Update register layout title 2026-06-11 10:58:59 +02:00
gitea_admin 8faba805e4 Rename VSF register layout 2026-06-11 10:58:12 +02:00
gitea_admin 8b7d5ef985 Support warning score state 2026-06-11 07:56:55 +02:00
gitea_admin c06be10abf Restore score state tokens 2026-06-11 07:50:18 +02:00
gitea_admin 5097d3d163 Require both fields for register button 2026-06-10 18:23:00 +02:00
gitea_admin 66d0740a03 Add login footer to VSF register step 1 2026-06-10 18:02:02 +02:00
gitea_admin fd654aa3c0 Add logo placeholders to VSF register step 1 2026-06-10 18:00:20 +02:00
gitea_admin 0ac500a889 Center VSF register social links 2026-06-10 17:59:52 +02:00
gitea_admin 283d295edc Add social login links to VSF register step 1 2026-06-10 17:58:14 +02:00
gitea_admin 08a93ca804 Use card strong text for social title 2026-06-10 17:56:30 +02:00
gitea_admin f699381506 Use typography strong text for social title 2026-06-10 17:54:52 +02:00
gitea_admin 5cffd1bf18 Rename social login section title 2026-06-10 17:49:32 +02:00
gitea_admin b9f74f3079 Tighten social login title spacing 2026-06-10 17:47:21 +02:00
gitea_admin e00b53bfad Add social login section title 2026-06-10 17:44:00 +02:00
gitea_admin d5bbe0e8c0 Update register step headings 2026-06-10 17:39:23 +02:00
gitea_admin 8aea488754 Update VSF register step 1 header actions 2026-06-10 17:37:58 +02:00
gitea_admin e20590eb69 Restore register form segment wrapper 2026-06-10 17:36:57 +02:00
gitea_admin 5ebd554544 Enable header action tab toggling 2026-06-10 17:35:09 +02:00
gitea_admin b8ac6bef44 Use large tab navigation for VSF header actions 2026-06-10 17:31:19 +02:00
gitea_admin 7781d7461f Restore register form segment padding 2026-06-10 17:30:34 +02:00
gitea_admin b92c36fe84 Align register form spacing to pattern 2026-06-10 17:27:10 +02:00
gitea_admin 12766755cf Move form section background to card 2026-06-10 17:25:10 +02:00
gitea_admin 60007216fc Add spacing before form actions 2026-06-10 17:21:45 +02:00
gitea_admin e9ee02eecf Align register form to template structure 2026-06-10 17:16:58 +02:00
gitea_admin ffd7c57318 Revert "Fix register form segment structure"
This reverts commit 6dfd2b6283.
2026-06-10 17:11:18 +02:00
gitea_admin 6dfd2b6283 Fix register form segment structure 2026-06-10 17:10:35 +02:00
gitea_admin de37c403d2 Right-align form section actions 2026-06-10 17:10:29 +02:00
gitea_admin 901bb7aa0b Align form section actions right 2026-06-10 17:08:22 +02:00
gitea_admin 9b9b0c943f Add form actions spacing 2026-06-10 17:07:23 +02:00
gitea_admin bb57018aa9 Add register form segment 2026-06-10 14:38:00 +02:00
gitea_admin 049b2e54ef Adjust form field group spacing 2026-06-10 14:36:25 +02:00
gitea_admin 59d48164a8 Increase form sections field spacing 2026-06-10 14:35:49 +02:00
gitea_admin 7c6db03117 Use variable height object card 2026-06-10 14:29:49 +02:00
gitea_admin 0cbf7a913e Remove variable-height object card actions 2026-06-10 14:28:47 +02:00
gitea_admin be34e0444d Add variable-height object card variant 2026-06-10 14:28:05 +02:00
gitea_admin 57fbe63b2e Set register step header tabs inactive 2026-06-10 14:21:47 +02:00
gitea_admin 8618e1ea3a Restore register step layout title 2026-06-10 14:20:25 +02:00
gitea_admin ccd5f74594 Remove register step heading 2026-06-10 14:20:07 +02:00
gitea_admin 91a3032faa Make register step spacing responsive 2026-06-10 14:18:16 +02:00
gitea_admin 726c9e59f6 Reduce register step card offset 2026-06-10 14:11:28 +02:00
gitea_admin 97b6a4f692 Increase register step header spacing 2026-06-10 14:10:45 +02:00
gitea_admin b6b305d084 Restore register step header 2026-06-10 14:09:47 +02:00
gitea_admin eba76ac365 Center VSF register step object card 2026-06-10 14:08:38 +02:00
gitea_admin d5a36657bb Update register step hero text 2026-06-10 14:02:58 +02:00
gitea_admin f86f9fde33 Update VSF register layout title 2026-06-10 13:59:31 +02:00
gitea_admin f1df586d4e Add VSF Register Step 1 layout 2026-06-10 13:58:26 +02:00
gitea_admin 96d7915bfb Rename VSF portal header action buttons 2026-06-10 13:54:56 +02:00
gitea_admin 3ffeb925f9 Reduce portal header brand on mobile 2026-06-10 13:50:33 +02:00
gitea_admin 7e86135d14 Adjust brand title for mobile 2026-06-10 13:48:16 +02:00
gitea_admin 5d1412d874 Remove duplicate VSF portal header public label 2026-06-10 13:45:47 +02:00
gitea_admin 105b0dbd50 Remove explanatory text from VSF portal header public 2026-06-10 13:44:10 +02:00
gitea_admin f74c1e0253 Remove next-element note from VSF portal header public 2026-06-10 13:42:40 +02:00
gitea_admin b56111a1bb Wrap VSF welcome heading in transparent card 2026-06-10 13:39:59 +02:00
gitea_admin 07b0cee987 Use typography H1 in VSF portal header public 2026-06-10 13:36:46 +02:00
gitea_admin a2c035ea5e Add welcome heading to VSF portal header public 2026-06-10 13:35:28 +02:00
gitea_admin ad31d91c7b Replace VSF portal header menu with link buttons 2026-06-10 13:34:38 +02:00
gitea_admin b4660fa893 Update VSF portal header public tabs 2026-06-10 13:32:54 +02:00
gitea_admin cc9103bd6f Add VSF portal header public pattern 2026-06-10 13:28:45 +02:00
gitea_admin a50ed1d8e8 Remove gridfield and tune pulldown spacing 2026-06-10 13:27:33 +02:00
gitea_admin 9f99482a93 Add gridfield component 2026-06-10 13:22:40 +02:00
gitea_admin e4fb7250ed Align mobile pulldown layout 2026-06-10 13:13:23 +02:00
gitea_admin a4a5dd6fa1 Tighten stacked label spacing 2026-06-10 13:08:47 +02:00
gitea_admin 4367999e75 Fix mobile pulldown label spacing 2026-06-10 13:05:04 +02:00
gitea_admin 27848d0a23 Tighten mobile label spacing 2026-06-10 13:02:07 +02:00
gitea_admin c7928436bb Revert mobile label spacing tweak 2026-06-09 13:58:15 +02:00
gitea_admin 369d0d882f Use small mobile label spacing 2026-06-09 13:57:38 +02:00
gitea_admin 56a9d712ec Revert mobile label spacing changes 2026-06-09 13:41:14 +02:00
gitea_admin 5e605fd93a Reduce mobile label line height 2026-06-09 13:33:08 +02:00
gitea_admin ee3a97ac1f Tighten mobile label spacing 2026-06-09 13:28:30 +02:00
gitea_admin 5c520aefaf Fix mobile interactive label spacing 2026-06-09 13:27:04 +02:00
gitea_admin 4a3c939005 Tighten pulldown panel width 2026-06-09 10:51:27 +02:00
gitea_admin dc092fb2d9 Fix card group hidden state 2026-06-09 09:13:08 +02:00
gitea_admin a5e286fbc6 feat: add empty score bar example 2026-06-05 08:06:07 +02:00
gitea_admin 6dff6380ef Color large table load more row 2026-06-04 19:45:12 +02:00
gitea_admin 2b7de07907 Styleguide: make load-more cards gray 2026-06-04 19:42:46 +02:00
gitea_admin 85b8926877 Stripe large table rows by visible order 2026-06-04 19:40:49 +02:00
gitea_admin 2a21a4550c Simulate server-side load more 2026-06-04 18:44:58 +02:00
gitea_admin b15e7525ce Contain large table rows within width 2026-06-04 18:40:57 +02:00
gitea_admin 2782f3b024 Constrain load more navigation card width 2026-06-04 18:39:08 +02:00
gitea_admin ff18fd49bc Add load more navigation card row 2026-06-04 18:37:43 +02:00
gitea_admin ab17a5e1fa Simulate server-side type-ahead search 2026-06-04 18:35:21 +02:00
gitea_admin c5492ff8df Switch large table search to submit 2026-06-04 18:33:28 +02:00
gitea_admin 83c1eaaf34 Rename search field placeholder 2026-06-04 18:29:20 +02:00
gitea_admin a3b5ea3bf0 Embed interactive search field in large table 2026-06-04 18:28:51 +02:00
gitea_admin 69855cbe57 Remove search field preview 2026-06-04 18:24:48 +02:00
gitea_admin a15410b7f4 Add search field component preview 2026-06-04 18:24:09 +02:00
gitea_admin 343b8ac90f Fix large table search visibility 2026-06-04 18:18:00 +02:00
gitea_admin 9ab23c47cc Add large table search filter 2026-06-04 18:12:57 +02:00
gitea_admin fc86eb0697 Enlarge large table sort triangles 2026-06-04 18:10:17 +02:00
gitea_admin 1b723f9b4d Stabilize large table sort indicators 2026-06-04 18:09:42 +02:00
gitea_admin 3f0fdf217e Use triangle sort indicators 2026-06-04 18:08:26 +02:00
gitea_admin e4eba55561 Make large table sort icons bolder 2026-06-04 18:07:23 +02:00
gitea_admin 8b0b508d24 Refine large table sort icons 2026-06-04 18:05:10 +02:00
gitea_admin 9f6745d044 Add sortable large table headers 2026-06-04 18:04:07 +02:00
gitea_admin 58aabfc873 Adjust large table row colors 2026-06-04 18:00:47 +02:00
gitea_admin 90c997a855 Add large table component preview 2026-06-04 17:59:02 +02:00
gitea_admin fb00d89fe3 Make left navigation items selectable 2026-06-04 17:53:45 +02:00
gitea_admin d81a1a743b Remove left navigation toggle workaround 2026-06-04 17:52:58 +02:00
gitea_admin 2a5f96369f Left align link menu items 2026-06-04 17:52:13 +02:00
gitea_admin a17525c441 Add mobile spacing above left navigation content 2026-06-04 17:51:17 +02:00
gitea_admin 013bdbdec6 Add bottom margin to left navigation card 2026-06-04 17:50:31 +02:00
gitea_admin f5f012dd5c Fix left navigation toggle rendering 2026-06-04 17:49:54 +02:00
gitea_admin 77543b3f74 Harden left navigation toggle behavior 2026-06-04 17:48:48 +02:00
gitea_admin 581301d500 Restore small right margin for left navigation card 2026-06-04 17:47:29 +02:00
gitea_admin fd1904d878 Remove right margin from left navigation card 2026-06-04 17:46:52 +02:00
gitea_admin cd835b5295 Tighten left navigation card margins 2026-06-04 17:46:16 +02:00
gitea_admin f76f4b4322 Remove left navigation wrapper card 2026-06-04 17:45:17 +02:00
gitea_admin 72b7a93f23 Move left navigation spacing to margins 2026-06-04 17:44:17 +02:00
gitea_admin 4804612d4f Normalize left navigation card padding 2026-06-04 17:43:09 +02:00
gitea_admin 68a8a1c1f6 Adjust left navigation card spacing 2026-06-04 17:42:57 +02:00
gitea_admin 5731fd6fdc Keep left navigation toggle active on mobile 2026-06-04 17:41:38 +02:00
gitea_admin 3611d9732f Add mobile toggle to left navigation 2026-06-04 17:38:21 +02:00
gitea_admin f6159f92eb Add left navigation pattern 2026-06-04 17:34:20 +02:00
gitea_admin aabe66cef4 Add stacked links menu item variant 2026-06-04 17:29:17 +02:00
gitea_admin cfc933f3c1 Remove status pulldown from left-only options row 2026-06-04 14:31:16 +02:00
gitea_admin be83f6e69c Add left-only options row variant 2026-06-04 14:30:00 +02:00
gitea_admin 128117824c Update portal sync flow 2026-06-04 11:19:40 +02:00
gitea_admin 1f74075dcd Add basic card component example 2026-06-04 11:18:13 +02:00
gitea_admin 0b8ec3f5e9 Sync both portals in one script 2026-06-03 16:28:31 +02:00
gitea_admin 6ef87f843b Support Naurua styleguide export 2026-06-03 16:25:26 +02:00
gitea_admin f59701ce74 Rename NAURUA override section 2026-06-03 16:08:08 +02:00
gitea_admin 7a81c4ecae Add NAURUA foundation overrides 2026-06-03 16:00:11 +02:00
gitea_admin b91188dd85 Add mobile VSF meldungen tabs 2026-06-03 15:50:57 +02:00
gitea_admin 9f104dccf3 Fix VSF meldungen group headings 2026-06-03 15:46:00 +02:00
gitea_admin 12883786a6 Update VSF meldungen layout 2026-06-03 15:45:08 +02:00
gitea_admin fb5baffc01 Fix notifications pattern desktop sizing 2026-06-03 15:36:13 +02:00
gitea_admin b1af9b3e6b Fix VSF meldungen overflow on small viewports 2026-06-03 14:02:28 +02:00
gitea_admin 2e07b47a18 Fix portal header tab color mapping 2026-06-02 19:56:53 +02:00
gitea_admin 6c42490b89 Fix tab navigation content variant colors 2026-06-02 19:50:52 +02:00
gitea_admin 8424b42a7d Fix tab navigation color inversion 2026-06-02 19:49:21 +02:00
gitea_admin c370bd3836 Add notification card min width foundation token 2026-06-02 19:44:54 +02:00
gitea_admin 9267b2fb70 Increase notification card minimum width 2026-06-02 19:42:40 +02:00
gitea_admin 09455ba49c Rename notification title example to Kaufsignal 2026-06-02 19:41:20 +02:00
gitea_admin 9e41192714 Update notification title example text 2026-06-02 19:38:49 +02:00
gitea_admin e7ed564ad9 Make notification title segment auto height 2026-06-02 19:36:47 +02:00
gitea_admin 9c8db407b1 Make notification title segment variable 2026-06-02 19:34:25 +02:00
gitea_admin 7f01e0029f Fix notification title segment height 2026-06-02 19:20:19 +02:00
gitea_admin 047257487b Add notifications pattern with title variant 2026-06-02 19:17:58 +02:00
gitea_admin 6f42dd6e9f Fix portal header tab state colors 2026-06-02 18:07:36 +02:00
gitea_admin a8066e4684 Add yellow notifications pattern variant 2026-06-02 12:14:09 +02:00
gitea_admin 75a243a611 Adjust notifications small height 2026-06-02 09:33:14 +02:00
gitea_admin 701b081232 Add in-content large tab navigation variant 2026-06-02 08:33:25 +02:00
gitea_admin 246e5e9a8b Remove local tab color overrides from card group pattern 2026-06-01 18:08:16 +02:00
gitea_admin a457ece614 Swap active and inactive styling for large tab navigation 2026-06-01 18:06:06 +02:00
gitea_admin 59eabd8882 Rename VSF Meldungen navigation link to Mehr laden 2026-06-01 17:28:22 +02:00
gitea_admin bfbfdcfc66 Move tab navigation cards inside group cards 2026-06-01 17:27:33 +02:00
gitea_admin be861d07a4 Add navigation card to both VSF Meldungen tabs 2026-06-01 17:26:14 +02:00
gitea_admin 236d9cf1f2 Add notifications sizing tokens and group-card variant rule 2026-06-01 17:24:18 +02:00
gitea_admin 12f16b9813 Align Meldungen notification structure and logic with notifications pattern 2026-06-01 17:18:39 +02:00
gitea_admin acc584d6e7 Limit notification width equalization to two-column rows 2026-06-01 17:17:16 +02:00
gitea_admin 0762aec772 Add three extra notification cards to Updates tab for testing 2026-06-01 17:15:27 +02:00
gitea_admin 1d0c6b4cf0 Match Meldungen notification behavior to notifications pattern 2026-06-01 17:14:25 +02:00
gitea_admin fc8af411b0 Remove fixed-width notification card sizing classes in Meldungen 2026-06-01 17:12:26 +02:00
gitea_admin 0b6d3cec41 Remove forced full-width context from Meldungen card group 2026-06-01 17:10:40 +02:00
gitea_admin 05fd13c34c Revert notification width refactor in VSF Meldungen 2026-06-01 17:08:30 +02:00
gitea_admin ad4ab5b49d Align notification card width behavior with VSF list detail layout 2026-06-01 17:07:58 +02:00
gitea_admin 835f177ab2 Force equal full-width notification cards inside group cards 2026-06-01 16:53:09 +02:00
gitea_admin db169cdc2f Wrap notification cards in group cards for both tabs 2026-06-01 16:51:41 +02:00
gitea_admin ce964e21e3 Add keyboard-nav notification card group to VSF Meldungen 2026-06-01 16:49:53 +02:00
gitea_admin ccf032d043 Adjust notifications text segment fixed height to 150px 2026-06-01 16:48:25 +02:00
gitea_admin 632de4aef5 Add semantic token for notifications text-segment fixed height 2026-06-01 16:47:06 +02:00
gitea_admin 8da817bf65 Fix spacing: keep small gap before options row in VSF Meldungen 2026-06-01 16:46:03 +02:00
gitea_admin 8b5e4e1826 Apply VSF intro-block spacing classes to Meldungen title 2026-06-01 16:44:23 +02:00
gitea_admin 4f77f08cba Enforce equal notification card widths across wrapped rows 2026-06-01 16:39:24 +02:00
gitea_admin 75a7d6d4ca Add Meldungen transparent card after options row 2026-06-01 16:37:45 +02:00
gitea_admin 98168722b6 Fix notifications pattern width behavior and text-segment height 2026-06-01 16:36:29 +02:00
gitea_admin 328e1652ec Remove portal header variant helper labels from VSF Meldungen 2026-06-01 16:31:31 +02:00
gitea_admin 7624ace59f Set notifications pattern desktop size to company card bounds 2026-06-01 16:31:10 +02:00
gitea_admin 89d899e694 Add portal header pattern interactions to VSF Meldungen 2026-06-01 16:29:49 +02:00
gitea_admin 95b25a2d22 Extract notification card into notifications pattern 2026-06-01 16:29:13 +02:00
gitea_admin 3d85fe63e7 Add portal header with options row pattern to VSF Meldungen 2026-06-01 16:27:31 +02:00
gitea_admin 2bc55492af Trim VSF Meldungen page content after H1 2026-06-01 16:24:09 +02:00
gitea_admin be0f937fe9 Restore full VSF Meldungen layout content 2026-06-01 16:20:38 +02:00
gitea_admin 3867fe6c57 Rename VSF spezifisch page to VSF Meldungen 2026-06-01 16:16:35 +02:00
gitea_admin 5d4288e6d4 Add VSF Spezifisch page to index 2026-06-01 16:15:43 +02:00
gitea_admin 8816b70ed7 Add VSF specific layout stub page 2026-06-01 16:13:25 +02:00
gitea_admin e94f00246b Swap tab background and text colors in card keyboard navigation pattern 2026-06-01 12:05:39 +02:00
gitea_admin d92817f179 feat(skill): add styleguide-anwendung skill for strict 1:1 portal usage 2026-06-01 11:48:54 +02:00
gitea_admin 1693757359 docs: enforce strict 1:1 pattern adoption with verification criteria 2026-06-01 11:47:57 +02:00
gitea_admin 0e2f734bf6 docs: tighten styleguide application skill with best-practice guardrails 2026-06-01 11:47:11 +02:00
gitea_admin 6efe9a90ae docs: add normative skill draft for styleguide application in portals 2026-06-01 11:45:27 +02:00
gitea_admin d5794576d1 Add unlabeled variant for multi-line input 2026-05-30 08:20:11 +02:00
gitea_admin afaff14c82 Add unlabeled variants for pulldown, input, and radio 2026-05-30 08:19:32 +02:00
gitea_admin ccc39c4acf Fix mobile overlay pulldown alignment to prevent viewport overflow 2026-05-29 17:50:48 +02:00
gitea_admin 14b995f68a Fix pulldown panel viewport fallback for iOS 2026-05-29 17:44:24 +02:00
gitea_admin 46f36f89cf Adjust V2 list card title segments to darkbrown 2026-05-29 16:14:53 +02:00
gitea_admin bc6a058555 Fix unified score-state box model across chart states 2026-05-29 16:04:00 +02:00
gitea_admin 0653dd923d Adjust form sections pattern interaction alignment with fixed label token 2026-05-29 15:18:34 +02:00
gitea_admin bbf212bbf9 Fix object-group-card min-width on VSF list overview overlay card 2026-05-29 15:11:07 +02:00
gitea_admin 075740e603 Delete confirmation: remove forced label min-width in input row 2026-05-29 14:59:56 +02:00
gitea_admin bc522af2a5 Pulldown: move stable trigger width to generic component rules 2026-05-29 14:55:18 +02:00
gitea_admin c1fb1a74a2 Pulldown single mode: show selected label instead of count 2026-05-29 14:49:12 +02:00
gitea_admin f9520658c8 Pulldown demo: make long selected-state test interactive 2026-05-29 14:48:05 +02:00
gitea_admin bc137d4206 Pulldown: robust long-value trigger and panel width/wrap behavior 2026-05-29 14:47:08 +02:00
gitea_admin 9b77279e76 Fix overlay dialog cards to host interactive panels 2026-05-29 14:29:26 +02:00
gitea_admin 862701ad62 Fix mobile label spacing for variable-width input labels 2026-05-29 14:22:22 +02:00
gitea_admin b4a365a218 Adjust input labels to content width with larger right spacing 2026-05-29 14:21:45 +02:00
gitea_admin 4be0ceb565 Add gray company-count segment to left list card 2026-05-29 13:57:37 +02:00
gitea_admin 7ee05c24b0 Fix three-column text layout body margins 2026-05-29 13:55:32 +02:00
gitea_admin b003eb7349 Update VSF overview V2 title to Meine Listen 2026-05-28 14:49:27 +02:00
gitea_admin 98e71902ea Align VSF overview V2 intro spacing behavior with detail layout 2026-05-28 14:48:54 +02:00
gitea_admin 0d67e8fe6c Increase intro top spacing and remove intro gap in VSF detail layout 2026-05-28 14:47:28 +02:00
gitea_admin b389150a2b Restore intro gap in VSF list detail layout 2026-05-28 14:46:31 +02:00
gitea_admin 03cb1a6771 Remove intro block gap in VSF list detail layout 2026-05-28 14:44:33 +02:00
gitea_admin e4e361b9bd Align VSF detail intro structure with transparent-card setup 2026-05-28 14:40:54 +02:00
gitea_admin f77704d87e Remove VSF list overview layout page and references 2026-05-28 14:40:06 +02:00
gitea_admin 93ca581a72 Remove vertical padding from transparent card component 2026-05-28 14:38:19 +02:00
gitea_admin 7ce5933a48 Preserve overlay card size behavior by removing forced target sizing 2026-05-28 14:36:06 +02:00
gitea_admin d2a66c6c5b Add overlay host wrapper behavior for consistent target card height 2026-05-28 14:35:23 +02:00
gitea_admin b3594d3f78 Make VSF cards wrap by available width with per-card overlay stage 2026-05-28 14:29:26 +02:00
gitea_admin 166b9ce174 Add second VSF card with create-list layout beside existing list card 2026-05-28 14:26:27 +02:00
gitea_admin 158acca6da Remove layout-3 heading from VSF overview V2 2026-05-28 14:18:00 +02:00
gitea_admin 863e575f3e Replace ID-scoped VSF list-card overlay width override with reusable context class 2026-05-28 14:16:53 +02:00
gitea_admin c0a6e13278 Add VSF list card layout 3 with edit/delete dialog behavior 2026-05-28 13:31:03 +02:00
gitea_admin 0049127743 Place VSF overview intro title and text inside transparent card 2026-05-28 13:28:09 +02:00
gitea_admin 0af4a94507 Set intro text color via layout tokenized CSS rule 2026-05-28 13:27:44 +02:00
gitea_admin 4d34555a80 Remove text-pattern label and preview surface in VSF overview V2 2026-05-28 13:26:54 +02:00
gitea_admin 30f9c3c204 Copy portal-header interaction scripts into VSF overview V2 2026-05-28 13:25:47 +02:00
gitea_admin 2a7c511a22 Add 60-percent text pattern below VSF overview V2 title 2026-05-28 13:23:42 +02:00
gitea_admin 6379207d16 Remove portal-header variant label from VSF overview V2 2026-05-28 13:22:41 +02:00
gitea_admin 4a87de86c2 Add list title heading to VSF overview V2 intro 2026-05-28 13:22:20 +02:00
gitea_admin 45a2c3f084 Embed portal-header options-row variant in VSF overview V2 2026-05-28 13:22:01 +02:00
gitea_admin 9a803e4369 Add variant label to VSF Listen Übersicht Seite V2 2026-05-28 13:20:30 +02:00
gitea_admin 20bdb04c0e Add VSF Listen Übersicht Seite V2 layout scaffold 2026-05-28 13:20:03 +02:00
gitea_admin fab59b8f89 Arrange VSF cards in shared row-wise object-card grid 2026-05-28 12:32:17 +02:00
gitea_admin 4daf7f7872 Remove legacy overlay overrides and restore template card structure 2026-05-28 12:29:58 +02:00
gitea_admin 6f5c96a120 Restore VSF list-card interaction script on overview page 2026-05-28 12:20:13 +02:00
gitea_admin 413fc913e5 Restore object-group-card width rules on first two VSF list cards 2026-05-28 12:16:21 +02:00
gitea_admin bf41a4f8bf Align VSF overview overlay cards to group-card width and height 2026-05-28 12:14:45 +02:00
gitea_admin e88baa8bd4 Restore responsive min-max widths on VSF layout cards by fixing grid item classes 2026-05-28 12:13:12 +02:00
gitea_admin 4ca8a93919 Fix overlapping VSF layout-3 cards by matching template structure 2026-05-28 12:11:36 +02:00
gitea_admin 380dc608a1 Fix layout-3 card dimensions by restoring object-card class on card articles 2026-05-28 12:06:25 +02:00
gitea_admin 499b549f30 Arrange VSF cards in shared object-group grid and remove layout headings 2026-05-28 12:04:22 +02:00
gitea_admin 746d5d0e2f Fix VSF layout-3 card width by applying list-card scope 2026-05-28 12:02:38 +02:00
gitea_admin 58e7bd164d Add two VSF layout-3 cards and one layout-1 card to overview page 2026-05-28 12:01:14 +02:00
gitea_admin 3b2b9784a2 Add VSF Listen Übersicht Seite layout without group cards 2026-05-28 11:57:40 +02:00
gitea_admin 1583c2e892 Replace Meldungen overlay content with sectioned form and checkbox save flow 2026-05-28 11:44:50 +02:00
gitea_admin f784bbb9ff Fix overlay pattern dimming and align VSF pages to shared overlay dialog contract 2026-05-28 11:41:04 +02:00
gitea_admin 248ce908c0 Add Meldungen overlay card with layout-scoped top offset and dialog interactions 2026-05-28 11:38:38 +02:00
gitea_admin b71544d95f Add group-card h2 variant sandwich menu and align VSF page to component template 2026-05-28 11:34:37 +02:00
gitea_admin 0538f5d868 Align Meldungen sandwich menu with right token-based inset 2026-05-28 11:32:44 +02:00
gitea_admin 4f3794c9a7 Restore Meldungen heading left alignment with card body text 2026-05-28 11:31:55 +02:00
gitea_admin cd4e550969 Fix Meldungen header row by overriding group-card heading flex basis 2026-05-28 11:30:49 +02:00
gitea_admin dad080fe7d Add small sandwich menu button to Meldungen group card header 2026-05-28 11:29:28 +02:00
gitea_admin 5bdd228f7e Replace inline notification toggle style with class-based state 2026-05-28 11:18:55 +02:00
gitea_admin 2792ef6fb3 Add mobile spacing-large margin below both VSF group boxes 2026-05-28 11:17:49 +02:00
gitea_admin f99332b890 Fix Meldungen mobile toggle by using explicit display none 2026-05-28 11:15:08 +02:00
gitea_admin fb2c88b1ba Set mobile Meldungen toggle to full width with large bottom spacing 2026-05-28 11:14:18 +02:00
gitea_admin 28274b7f48 Add mobile-only toggle to show and hide Meldungen cards 2026-05-28 11:12:52 +02:00
gitea_admin f5662ca1ed Add spacing-large margin after both group card component variants 2026-05-28 11:11:24 +02:00
gitea_admin c0f90ba739 Wrap object cards in group card with Unternehmen heading 2026-05-28 11:05:43 +02:00
gitea_admin e56645583c Update Meldungen button labels to Details 2026-05-28 11:01:37 +02:00
gitea_admin e05db71b33 Add object card shared-width row logic to VSF detail page 2026-05-28 10:56:54 +02:00
gitea_admin 1fde3795c8 Restore object card grid row wrap behavior on VSF detail page 2026-05-28 10:55:14 +02:00
gitea_admin 9a0ac87c78 Remove object-card width override to keep pattern min max widths 2026-05-28 10:54:30 +02:00
gitea_admin 5dd7b18694 Add desktop two-column layout with six object cards on VSF detail page 2026-05-28 10:53:22 +02:00
gitea_admin 0c46113abd Align VSF page group card with new H2 heading variant 2026-05-28 10:51:01 +02:00
gitea_admin 442d90520a Replace inline group-card heading spacing with component CSS class 2026-05-28 10:49:21 +02:00
gitea_admin 16b5a99923 Align group card heading left edge with card body text via token margin 2026-05-28 10:47:18 +02:00
gitea_admin ab200007db Wrap group card heading in transparent card for consistent inner margins 2026-05-28 10:45:49 +02:00
gitea_admin 10f041da91 Align group card h2 with foundation heading and white text 2026-05-28 10:44:50 +02:00
gitea_admin 4475885368 Add second group card variant with h2 heading 2026-05-28 10:43:57 +02:00
gitea_admin 5e0fa182dd Set Meldungen heading to white using token-based utility class 2026-05-28 10:41:05 +02:00
gitea_admin 9819aa2c5b Replace group card label with Meldungen heading 2026-05-28 10:40:40 +02:00
gitea_admin 53ec49b845 Set list page title and remove title help icon 2026-05-28 10:39:26 +02:00
gitea_admin 4043397bf2 Increase VSF list detail group card column width to 30 percent 2026-05-28 10:37:25 +02:00
gitea_admin 2d4a1fc984 Align white notification card variant with component template 2026-05-28 10:36:56 +02:00
gitea_admin 6f0cdcd668 Make sg-body margin conditional on sibling content 2026-05-28 10:35:28 +02:00
gitea_admin a21950773c Override group card item width to full in VSF list detail layout 2026-05-28 10:31:53 +02:00
gitea_admin d7ddc4f910 Stack group card notification cards vertically in VSF list detail layout 2026-05-28 10:30:53 +02:00
gitea_admin f55e568e2a Add left 15 percent group card with three notification variants 2026-05-28 10:30:08 +02:00
gitea_admin 90eb245d05 Refine white notification card text via card variant token cascade 2026-05-28 10:29:57 +02:00
gitea_admin d1a30c726e Set white notification header text to dark 2026-05-28 10:29:09 +02:00
gitea_admin 6ecedc90a8 Add white variant to notification card 2026-05-28 10:27:38 +02:00
gitea_admin b97e1d4d47 Add missing button and mode-toggle interactions to VSF list detail page 2026-05-28 10:26:50 +02:00
gitea_admin 377f23ff6e Add reusable VSF list detail layout page and module 2026-05-28 10:24:16 +02:00
gitea_admin 1ec247f62f Refine VSF list card token cascade and docs 2026-05-28 10:16:12 +02:00
gitea_admin ea38a2cee1 Add Component Notification Card with signal variants 2026-05-28 10:14:56 +02:00
gitea_admin 4e940cb5ff Consolidate list card dialog interaction into layout 3 2026-05-28 10:05:08 +02:00
gitea_admin b59ecd40e1 Refactor VSF overlay layout to token-based pattern cascade 2026-05-28 09:38:18 +02:00
gitea_admin 31d923c3ca Increase overlay spacing before confirmation input to spacing-large 2026-05-28 09:37:07 +02:00
gitea_admin 749b287f16 Rename delete confirmation overlay pattern to overlay card 2026-05-28 09:36:04 +02:00
gitea_admin ad5e38aadf Fix layout 4 overlay centering by constraining delete stage width 2026-05-28 09:33:36 +02:00
gitea_admin 308d5a91c4 Align VSF list card layouts with object-group-card structure 2026-05-28 09:32:19 +02:00
gitea_admin fedb34ed83 Remove local width override and align layout 4 with object-group-card container 2026-05-28 09:29:14 +02:00
gitea_admin 33b50d4ccd Restore layout 4 card width to object-group-card max width 2026-05-28 09:28:17 +02:00
gitea_admin 0f9f97cbfa Fix layout 4 overlay alignment and close default sandwich state 2026-05-28 09:26:56 +02:00
gitea_admin 5e200c57ed Add layout 4 list delete state with confirmation overlay 2026-05-28 09:24:55 +02:00
gitea_admin 6e55389ae3 Set inactive link button background equal to active variant 2026-05-28 09:22:56 +02:00
gitea_admin ca805d0621 Align layout 2 reset button with inactive link-button variant 2026-05-28 09:21:40 +02:00
gitea_admin 42d3f475ef Rename top score bar label to Medianscore 2026-05-28 09:20:03 +02:00
gitea_admin 1ca7de6b50 Remove median markers from VSF list card score bars 2026-05-28 09:19:27 +02:00
gitea_admin 4204bc2541 Add median subscores label above list card score bars 2026-05-28 09:18:53 +02:00
gitea_admin aa2843e9a4 Set layout 3 last two segments to white background 2026-05-28 09:17:45 +02:00
gitea_admin d0f975f811 Fix layout 3 footer anchoring and segment background 2026-05-28 09:16:02 +02:00
gitea_admin af32e2ed80 Add single-action footer segment to layout 3 list card 2026-05-28 09:14:18 +02:00
gitea_admin 6c9edf3942 Match list description spacing to company-card moat gap 2026-05-28 09:13:33 +02:00
gitea_admin c6917f8b02 Replace layout 3 placeholders with company-card top segment content 2026-05-28 09:12:21 +02:00
gitea_admin 2b3d6d98d5 Restore card body padding tokens in VSF list card layout 2026-05-28 09:11:23 +02:00
gitea_admin 22a0c15bbe Normalize layout 3 card segment classes to components-cards contract 2026-05-28 09:10:18 +02:00
gitea_admin c6b88510d1 Apply cards component body padding to layout 3 placeholder segments 2026-05-28 09:08:22 +02:00
gitea_admin 7768563883 Replace layout 3 top content with two darkgray placeholder segments 2026-05-28 09:07:28 +02:00
gitea_admin d189ea6fa8 Fix layout 3 by separating lightgrey segments from content wrappers 2026-05-28 09:06:24 +02:00
gitea_admin d69718d87a Restore card segment padding in layout 3 top body segments 2026-05-28 09:04:37 +02:00
gitea_admin e498743c7a Populate layout 3 list card content based on company card 2026-05-28 09:01:35 +02:00
gitea_admin ccf215accb Set delete target dim overlay color to black 2026-05-28 08:58:18 +02:00
gitea_admin d87ac8edbd Fix delete overlay centering and enforce 80 percent width 2026-05-28 08:56:47 +02:00
gitea_admin e6acfcae4f Adjust delete overlay dimming, sizing, and object card composition 2026-05-28 08:55:57 +02:00
gitea_admin bf7a6675fb Add delete confirmation overlay pattern with tokens and docs 2026-05-28 08:51:04 +02:00
gitea_admin 9e16eb5480 Fix list card title assignment for layout 3 only 2026-05-28 08:43:20 +02:00
gitea_admin 378ef263aa Set layout 3 list card title to NAME DER LISTE 2026-05-28 08:42:49 +02:00
gitea_admin c58080869f Set list card sandwich menu entries 2026-05-28 08:42:09 +02:00
gitea_admin 7d0ff6bf9c Add layout 3 list card scaffold with small sandwich menu 2026-05-28 08:42:00 +02:00
gitea_admin f4d4dca81a Use interactive-elements disabled states in max-list layout 2026-05-28 08:38:19 +02:00
gitea_admin 7d441d2fc9 Fix max-list warning placement above form 2026-05-28 08:37:24 +02:00
gitea_admin b780048f27 Add VSF list card layout for max list limit state 2026-05-28 08:36:20 +02:00
gitea_admin 57cb1bf99b Remove redundant form heading from VSF List Card new list form 2026-05-28 08:32:38 +02:00
gitea_admin 7fc8214872 Unify form input max width across interactive elements and form sections 2026-05-28 08:31:29 +02:00
gitea_admin e1cf43abc0 Increase single and multi line input max width by 100px 2026-05-28 08:28:43 +02:00
gitea_admin fd1a345a65 Adjust form sections pattern max width by 100px 2026-05-28 08:27:23 +02:00
gitea_admin 687ef5b96e Right-align form section actions with content-width buttons 2026-05-28 08:23:40 +02:00
gitea_admin d1b615a576 Apply unified min/max form frame and remove legacy button width overrides 2026-05-28 08:19:47 +02:00
gitea_admin 5bac467735 Align form section action row width with input field row 2026-05-28 08:18:04 +02:00
gitea_admin 675c83d835 Constrain form section action buttons to form width 2026-05-28 08:16:37 +02:00
gitea_admin a15bd17c3f Adjust form sections pattern to full-width background 2026-05-28 08:14:44 +02:00
gitea_admin a0752f2a12 Apply no-padding form layout behavior to VSF list-card 2026-05-27 17:03:33 +02:00
gitea_admin 8ec83a0c15 Remove global padding from form-sections pattern 2026-05-27 17:03:04 +02:00
gitea_admin 2127eec001 Remove remaining double padding for card-embedded form sections 2026-05-27 17:01:03 +02:00
gitea_admin 70677fc556 Centralize form-sections padding behavior for card-embedded forms 2026-05-27 16:59:53 +02:00
gitea_admin f83c37358e Remove extra card-body padding in VSF list-card form layout 2026-05-27 16:59:06 +02:00
gitea_admin b680c09d85 Define mandatory modular CSS conventions for styleguide 2026-05-27 16:58:02 +02:00
gitea_admin e97dd47769 Rename VSF list-card form action button labels 2026-05-27 16:54:05 +02:00
gitea_admin 9166d67f22 Activate process button on VSF list-card form input 2026-05-27 16:53:04 +02:00
gitea_admin d94fd4e530 Match VSF list-card form structure 1:1 with form-sections pattern 2026-05-27 16:52:12 +02:00
gitea_admin 61a5360563 Add missing form action buttons to VSF list-card layout 2026-05-27 16:49:41 +02:00
gitea_admin f81081eed1 Set VSF list-card form segment background to light-grey token 2026-05-27 16:46:33 +02:00
gitea_admin 17169081e3 Add dedicated CSS module for VSF list-card pattern 2026-05-27 16:45:36 +02:00
gitea_admin 7cfbcb8023 Add rule for separate pattern/layout semantic token CSS modules 2026-05-27 16:44:42 +02:00
gitea_admin 96dd1ce1d5 Make VSF list card form markup strict 1:1 with interactive elements 2026-05-27 16:42:24 +02:00
gitea_admin d95150c78a Align list-card form fields with interactive-elements styling 2026-05-27 16:39:58 +02:00
gitea_admin 86ada4cf60 Set list creation form segment to light grey 2026-05-27 16:35:03 +02:00
gitea_admin d6b6146cbc Add VSF list card layout: Neue Liste anlegen Karte 2026-05-27 16:33:09 +02:00
gitea_admin 57b62dae64 Place company card moat value on shared score-bar grid start 2026-05-27 16:27:22 +02:00
gitea_admin a20cff0a7b Align company card moat value with analysis score bars 2026-05-27 16:24:32 +02:00
gitea_admin 593e06d927 Add VSF list card layout page with state variants 2026-05-27 16:22:42 +02:00
gitea_admin 824f137aeb Fix multiselect pulldown activation gating for sliders and radio 2026-05-27 11:05:01 +02:00
gitea_admin 78845c7913 Allow only local toggles to receive clicks in off state 2026-05-27 10:55:31 +02:00
gitea_admin be7aba2778 Block inactive radio choice clicks in multiselect pulldown 2026-05-27 10:53:41 +02:00
gitea_admin 422fcad1a9 Disable inactive radios in multiselect pulldown 2026-05-27 10:52:32 +02:00
gitea_admin aaf2310379 Keep local toggles opaque while dimming inactive controls 2026-05-27 10:50:20 +02:00
gitea_admin 6bdca92878 Keep multiselect sliders visually opaque in off state 2026-05-27 10:46:41 +02:00
gitea_admin 0be27e6a6a Gate multiselect sliders by local on off toggle 2026-05-27 10:45:38 +02:00
gitea_admin 3e99e1c242 Restore pulldown option activation behavior for off state 2026-05-27 10:42:46 +02:00
gitea_admin 341910b20b Keep multiselect option pulldowns active in off state 2026-05-27 10:41:03 +02:00
gitea_admin ecf6f2afee Clean multiselect slider state semantics and touch feedback 2026-05-27 10:39:33 +02:00
gitea_admin e9c1952e57 Keep multiselect pulldown sliders active in off state 2026-05-27 10:37:29 +02:00
gitea_admin 2d49a1dd18 Fix iOS tap highlight on inactive multiselect slider rows 2026-05-27 10:26:12 +02:00
gitea_admin d6480ae5ac Adjust local mode toggle label to table-label size 2026-05-26 15:12:06 +02:00
gitea_admin 872f63674c Align subsection score row height with overall rating 2026-05-26 13:45:07 +02:00
gitea_admin 7935c768a0 Show numeric score only for section score bars 2026-05-26 13:41:15 +02:00
gitea_admin 63b85982c4 Remove inline score color and use semantic label class 2026-05-26 13:40:33 +02:00
gitea_admin b213ec026b Force score value label to always render black 2026-05-26 13:39:12 +02:00
gitea_admin 4bb77b61fe Ensure score value inherits positive state color 2026-05-26 13:37:31 +02:00
gitea_admin 9f1ca19c1c Keep score value and recommendation on one line 2026-05-26 13:36:57 +02:00
gitea_admin 69189ba1c7 Adjust Gesamtbewertung score label placement in drawer pattern 2026-05-26 13:36:11 +02:00
gitea_admin 8ee90bb19b Clean text layout mobile column behavior without override exceptions 2026-05-26 11:47:19 +02:00
gitea_admin dfafe55e48 Keep text layout 2/3-column patterns multi-column on mobile 2026-05-26 11:45:55 +02:00
gitea_admin 6cc865d984 Fix text-layout pattern viewport overflow 2026-05-26 11:44:08 +02:00
gitea_admin ecd44a5e5c Rename next analysis text in VSF drawer intro 2026-05-26 11:42:26 +02:00
gitea_admin 61c6795d7e Align title help icon vertically in VSF drawer 2026-05-26 11:39:56 +02:00
gitea_admin e223c5deb4 Add help tooltip icon to fundamental analysis title 2026-05-26 11:38:43 +02:00
gitea_admin aafa61fd14 Rename next analysis label in VSF fundamental drawer 2026-05-26 11:37:44 +02:00
gitea_admin 6f77c87de4 Remove obsolete mode-toggle control card from VSF drawer template 2026-05-26 11:36:38 +02:00
gitea_admin 229c494b78 Include portal style build and commit in sync command 2026-05-26 11:33:03 +02:00
gitea_admin b5353a28cb Sync full styleguide docs including scripts to portal 2026-05-26 11:29:34 +02:00
gitea_admin c06d317e31 Centralize help-icon overlay behavior across styleguide demos 2026-05-26 09:43:30 +02:00
gitea_admin edbcc13db4 Replace hardcoded tooltip inset with foundation-token-derived value 2026-05-26 09:12:54 +02:00
gitea_admin 44bae893a3 Allow mobile tabs to expand while preserving label minimum width 2026-05-26 09:08:36 +02:00
gitea_admin 737ec8f2cb Use intrinsic mobile tab widths and remove legacy row-slot logic 2026-05-26 09:01:03 +02:00
gitea_admin b34ceda1e3 Restore non-wrapping mobile tabs and clamp help tooltip in viewport 2026-05-26 08:56:54 +02:00
gitea_admin 33921a3f6e Fix mobile overflow for tabs and help tooltips 2026-05-26 08:52:53 +02:00
gitea_admin 770cafd6cf Harden help overlay viewport fit on small iOS screens 2026-05-26 08:47:12 +02:00
gitea_admin 98b2c8cb31 Fix help icon overlay viewport handling on mobile 2026-05-25 13:57:20 +02:00
gitea_admin 2c119d33b9 Apply balanced mobile tab rows to VSF fundamental drawer 2026-05-25 09:15:55 +02:00
gitea_admin e61ec9a492 Fix mobile tab row balancing in keyboard-nav pattern 2026-05-25 09:14:51 +02:00
gitea_admin 9c6fd2d62f Align multiselect fallback width with semantic pattern token 2026-05-25 09:04:13 +02:00
gitea_admin ee2a24e012 Fix overlay layer for pulldown and sandwich panels 2026-05-25 08:55:47 +02:00
gitea_admin 5da2203517 Fix multiselect label column collapse and restore control offset 2026-05-25 08:53:56 +02:00
gitea_admin 730cc137bb Fix multiselect pulldown control start alignment by panel label width 2026-05-25 08:52:09 +02:00
gitea_admin 2792104f45 Enforce style module import rule in skill and sync guard 2026-05-25 08:35:31 +02:00
gitea_admin 1d09b6f480 Resolve styleguide imports before syncing upstream CSS 2026-05-25 08:33:38 +02:00
gitea_admin b659bbc652 Clarify strict CSS read scope and streamline AGENTS guide 2026-05-25 08:32:00 +02:00
gitea_admin 3e9c273823 Split styleguide CSS into modular files per section/pattern/layout/page 2026-05-25 08:29:52 +02:00
gitea_admin e13ce0ad23 Increase multiselect pulldown row spacing between pulldown groups 2026-05-25 08:26:55 +02:00
gitea_admin 9a6db61677 Align multiselect pulldown mobile slider layout with slider component pattern 2026-05-25 08:14:54 +02:00
gitea_admin 87435dfd38 Fix multiselect pulldown radio labels to use existing activatable radio state styling 2026-05-25 08:11:24 +02:00
gitea_admin 90f7f40298 Fix disabled radio label alignment in radio component 2026-05-25 08:04:32 +02:00
gitea_admin d5ffc3c283 Sync activatable radio option label opacity with on/off state 2026-05-25 08:02:30 +02:00
gitea_admin 9951be0eb2 Limit normal pulldown open action to trigger button clicks 2026-05-25 07:59:15 +02:00
gitea_admin 8f9c699fff Normalize pulldown checkbox panel spacing by removing sg-body bottom margin 2026-05-25 07:57:46 +02:00
gitea_admin dc7a6bcc65 Remove pulldown checkbox list top-margin special rule 2026-05-25 07:57:06 +02:00
gitea_admin 522b448527 Stabilize activatable pulldown with one-time default initialization 2026-05-25 07:54:52 +02:00
gitea_admin cdfa2fe7de Remove nested filter pulldowns from activatable pulldown panel 2026-05-25 07:51:58 +02:00
gitea_admin dee4ce5f55 Normalize pulldown option handling to data attribute selector 2026-05-25 07:50:55 +02:00
gitea_admin 0868ec8fe0 Unify activatable pulldown state handling and remove double-toggle legacy 2026-05-25 07:49:31 +02:00
gitea_admin 825091cb28 Enforce inactive pulldown visuals while preserving selection 2026-05-25 07:44:01 +02:00
gitea_admin 9e97501b5c Preserve activatable pulldown selection across toggle 2026-05-25 07:42:23 +02:00
gitea_admin 11a9f3c6f3 Fix activatable pulldown state sync timing 2026-05-25 07:40:17 +02:00
gitea_admin 6a844f565c Fix activatable pulldown enabling behavior 2026-05-25 07:38:29 +02:00
gitea_admin c54283448a Apply radio choice label state decoupling globally 2026-05-25 07:34:50 +02:00
gitea_admin aef7fabb9c Keep radio option labels visually stable in activatable variant 2026-05-25 07:33:34 +02:00
gitea_admin bcd16e3077 Adjust interactive template activation and mobile slider layout 2026-05-25 07:30:23 +02:00
gitea_admin 604bbe6c99 fix(components): make slider preview frame and row width input-like 2026-05-25 07:23:16 +02:00
gitea_admin d7c8f09462 fix(components): apply input-like max width to slider component 2026-05-25 07:22:27 +02:00
gitea_admin f14f8f581c fix(components): adjust radio label spacing and mobile wrap 2026-05-25 07:21:23 +02:00
gitea_admin 17dfbf324a feat(components): add labels and dual options to radio single-choice 2026-05-25 07:20:17 +02:00
gitea_admin 07d3781c3b docs(styleguide): define shared form alignment rule across controls 2026-05-25 07:18:24 +02:00
gitea_admin 11780533fa fix(components): align activatable pulldown with label column 2026-05-25 07:16:39 +02:00
gitea_admin f4e98fc6d4 fix(components): keep activatable pulldown header inline on desktop 2026-05-25 07:12:59 +02:00
gitea_admin 102e391977 feat(components): add pulldown labels and activatable wrap behavior 2026-05-25 07:11:40 +02:00
gitea_admin 793878c92a fix(components): apply pulldown max-width in disabled state 2026-05-25 07:08:38 +02:00
gitea_admin f42bd57c7d feat(components): make pulldown responsive like single-line input 2026-05-25 07:07:56 +02:00
gitea_admin 758de215ed docs(agents): add local path for styleguide-erstellung skill 2026-05-25 07:07:10 +02:00
gitea_admin 94bc9f48fd Update multiselect pulldown to activation-toggle pattern 2026-05-25 06:59:50 +02:00
gitea_admin 74eaed57f1 Revert "Checkbox/Radio: bei aus Interaktionselement inkl. Labels ausgrauen, Schalter aktiv lassen"
This reverts commit f0225693bd.
2026-05-25 06:52:28 +02:00
gitea_admin 92f50094ec Revert "Clean interactive elements token cascade and sync docs"
This reverts commit 1ff7b59e3c.
2026-05-25 06:52:23 +02:00
gitea_admin 1ff7b59e3c Clean interactive elements token cascade and sync docs 2026-05-25 06:49:30 +02:00
gitea_admin f0225693bd Checkbox/Radio: bei aus Interaktionselement inkl. Labels ausgrauen, Schalter aktiv lassen 2026-05-23 10:34:09 +02:00
gitea_admin 3b135718b3 Aktivierungs-Schalter nicht ausgrauen und Abstand zu Controls auf spacing-large 2026-05-23 10:32:32 +02:00
gitea_admin e4a2872b17 Checkbox/Radio: Pattern-Label immer als eigene Zeile über Controls 2026-05-23 10:31:30 +02:00
gitea_admin bc52b755d2 Mobile Slider-Header Reihenfolge explizit auf Schalter vor Wert fixieren 2026-05-23 10:29:08 +02:00
gitea_admin 7abd6506e6 Aktivierbare Komponenten: kein Auto-Setzen von Werten bei Schalter an 2026-05-23 10:27:56 +02:00
gitea_admin 973e05dd73 Aktivierbarer Slider bei Schalter aus technisch deaktivieren 2026-05-23 10:25:43 +02:00
gitea_admin 8bc16561c1 Slider als clean grid template bereinigen und output-typografie entkoppeln 2026-05-23 10:24:43 +02:00
gitea_admin 0451329eda Sliderwert: sg-body-Margin im Slider-Scope neutralisieren 2026-05-23 10:22:34 +02:00
gitea_admin cfc38083b5 Sliderwert: harte Zeilenhöhe im Component-Scope entfernen 2026-05-23 10:21:49 +02:00
gitea_admin deb380b85e Sliderwert wie Label ausrichten: reine Grid-Zentrierung ohne Flex 2026-05-23 10:19:54 +02:00
gitea_admin ca17548669 Slider: sauberes Grid-Alignment ohne Transform-Hacks 2026-05-23 10:19:00 +02:00
gitea_admin e359894d95 Sliderwert vertikal auf Track-Mitte nachkalibrieren 2026-05-23 10:17:27 +02:00
gitea_admin f22aa2ef65 Sliderwert optisch auf Track-Mitte nachjustieren 2026-05-23 10:16:08 +02:00
gitea_admin 29b78aed68 Sliderwert vertikal exakt zur Slider-Zeile ausrichten 2026-05-23 10:15:02 +02:00
gitea_admin ead8446947 Slider mobile/header spacing und vertikale Ausrichtung der Werte korrigieren 2026-05-23 10:13:26 +02:00
gitea_admin e46eb330f2 Mobile Slider-Layout: Header (Schalter+Wert) und volle Breite für Slider-Zeile 2026-05-23 10:11:14 +02:00
gitea_admin 177a602879 Slider-Labelspalten im Component-Scope auf Inhaltsbreite reduzieren 2026-05-23 10:08:11 +02:00
gitea_admin 90716491e6 Aktivierbarer Slider: Grid-Layout auf volle Restbreite korrigieren 2026-05-23 10:06:54 +02:00
gitea_admin 3a3391cd6c Slider im Interactive Elements auf volle verfügbare Breite ausrichten 2026-05-23 10:06:01 +02:00
gitea_admin b06991e16f Slider layout in Interactive Elements korrigieren 2026-05-23 10:04:48 +02:00
gitea_admin 4278019c02 Interactive Elements: Aktivierung über Schalter statt Entfernen-Button 2026-05-23 10:01:42 +02:00
gitea_admin 857785da1b Keep company card metrics three-column on mobile 2026-05-23 09:42:15 +02:00
gitea_admin 07975655a9 Align activation toggle with semantic token cascade 2026-05-23 08:24:26 +02:00
gitea_admin 623b0912e8 Use small table-label font size for activation toggle text 2026-05-23 08:22:28 +02:00
gitea_admin 6452ec5a76 Place activation toggle labels inside switch track 2026-05-23 08:21:35 +02:00
gitea_admin 70940aa7c0 Force visibility of an/aus labels on activation toggle 2026-05-23 08:20:32 +02:00
gitea_admin b5fb68125b Ensure an/aus labels are visible on activation toggle 2026-05-23 08:19:52 +02:00
gitea_admin e7524ace89 Align activation toggle with existing external-label slider style 2026-05-23 08:19:06 +02:00
gitea_admin 15020ab410 Remove gray edge around activation toggle handle 2026-05-23 08:18:02 +02:00
gitea_admin fb28c77c00 Fix activation toggle handle visibility 2026-05-23 08:17:22 +02:00
gitea_admin 18e2c1d88c Fix activation toggle active-side text contrast 2026-05-23 08:16:13 +02:00
gitea_admin 8c884b4a53 Remove standalone activation toggle pattern page and index entry 2026-05-23 08:15:19 +02:00
gitea_admin 707048b58b Add an/aus activation toggle to interactive elements 2026-05-23 08:14:32 +02:00
gitea_admin ceac148df3 Add activation toggle pattern with inline an/aus chip 2026-05-23 08:13:56 +02:00
gitea_admin b8bba8d118 Use three-column distributed metrics in company card layout 2026-05-23 08:01:22 +02:00
gitea_admin 38e1e0369f Add distributed three-column text layout pattern 2026-05-23 07:46:59 +02:00
gitea_admin 13d0b86221 Fix pattern content inset drift with shared token and guardrail 2026-05-22 07:32:19 +02:00
gitea_admin e876ccc8ab Align card list intro with transparent card and 60% text pattern 2026-05-22 07:23:23 +02:00
gitea_admin ecfa2660ae Remove sg-card-list-page title-row styling 2026-05-22 07:19:49 +02:00
gitea_admin 94054e6402 Keep selected tab surface unchanged; white only for unselected tabs 2026-05-21 18:37:09 +02:00
gitea_admin e15948b348 Set card-group tab button backgrounds to white 2026-05-21 18:36:24 +02:00
gitea_admin f0debe844d Make mobile tab row fill width and wrap only at intrinsic minimum 2026-05-21 18:32:34 +02:00
gitea_admin 34f871e627 Set uniform mobile tab widths within min/max bounds for all tabs 2026-05-21 18:30:11 +02:00
gitea_admin c7517c65b4 Apply mobile width bounds to inactive tabs with preferred width 2026-05-21 18:28:47 +02:00
gitea_admin 28b94ec8a0 Use active-tab width switching within mobile min/max bounds 2026-05-21 18:15:29 +02:00
gitea_admin e2eb0fd4aa Make mobile tab widths clamp between current and plus-40-percent 2026-05-21 18:06:07 +02:00
gitea_admin 736c433679 Adjust mobile tab button min/max widths in card group pattern 2026-05-21 18:04:36 +02:00
gitea_admin 4245516adc Fix object-group-card mobile overflow by forcing full-width cards 2026-05-21 18:03:09 +02:00
gitea_admin 2a6dae1063 Normalize sandwich menu item spacing to match pulldown options 2026-05-21 17:33:07 +02:00
gitea_admin 4cabfe2daf Move sandwich menu into blue header and right-align mode toggle in controls card 2026-05-21 17:29:40 +02:00
gitea_admin da949403e8 Restore card overflow default and introduce reusable overlay-host card variant 2026-05-21 17:28:45 +02:00
gitea_admin 299932af77 Set inactive tab background to light gray in card tab group pattern 2026-05-21 17:21:35 +02:00
gitea_admin 49f283aba8 Move drawer controls from options row into single gray card segment 2026-05-21 17:20:17 +02:00
gitea_admin 5f00eb01f0 Fill TAM white content segment with provided market text 2026-05-21 17:12:06 +02:00
gitea_admin 37d7319304 Fill Marktbewertung white content segment with provided analysis text 2026-05-21 17:11:36 +02:00
gitea_admin d0c5368511 Align help icon vertically in inline text flow 2026-05-21 17:10:45 +02:00
gitea_admin 7edc2945e5 Add interactive help icons to all tab sub-card titles 2026-05-21 17:09:19 +02:00
gitea_admin 4f003a8709 Copy table and Graphik segments to Wachstum Profitabilität Stabilität tabs 2026-05-21 17:08:28 +02:00
gitea_admin d7ce8bdafb Fix Graphik segment by using body variant and remove local padding override 2026-05-21 17:07:37 +02:00
gitea_admin 04e607f526 Remove bottom padding from market valuation Graphik segment 2026-05-21 17:06:53 +02:00
gitea_admin 0f18bc6bdf Add gray Graphik segment after market valuation table 2026-05-21 17:05:13 +02:00
gitea_admin 517549ce6e Promote help-icon overlay stacking fix to component level 2026-05-21 17:03:50 +02:00
gitea_admin 8ec4aac772 Allow tooltip overflow through data-table context in Marktbewertung segment 2026-05-21 17:02:09 +02:00
gitea_admin 4aba1df526 Restore rounded corners for Marktbewertung card with visible overflow 2026-05-21 16:59:52 +02:00
gitea_admin acf2cbc961 Fix tooltip clipping by overriding card overflow after base card rule 2026-05-21 16:58:51 +02:00
gitea_admin 71467dd996 Raise open help-icon stacking level in Marktbewertung table segment 2026-05-21 16:58:03 +02:00
gitea_admin b06e47c1c3 Raise market valuation help tooltip layer above following segment 2026-05-21 16:57:12 +02:00
gitea_admin 84f4b2d43e Close cross-overlays and prevent help tooltip clipping in Marktbewertung 2026-05-21 16:56:06 +02:00
gitea_admin 1d9a536095 Align help-icon content and one-open-at-a-time behavior with template 2026-05-21 16:54:23 +02:00
gitea_admin de7b41ad82 Make data table help icons interactive in Marktbewertung tab 2026-05-21 16:52:40 +02:00
gitea_admin 3fe04276f6 Add gray data table segment to Marktbewertung tab 2026-05-21 16:51:17 +02:00
gitea_admin cce7f7c332 Add score bar segment below headers for four fundamental tabs 2026-05-21 16:49:34 +02:00
gitea_admin 8b6dc33b9e Set options row top spacing override to spacing-large 2026-05-21 16:47:30 +02:00
gitea_admin f932a7951f Match business model button to portal header inactive tab colors 2026-05-21 16:46:11 +02:00
gitea_admin 26b0d10991 Remove bottom margin from navigation card layout 2026-05-21 16:45:17 +02:00
gitea_admin 42a43cb1a5 Use global card-segment padding tokens for transparent card 2026-05-21 16:42:27 +02:00
gitea_admin c28853560d Standardize transparent card padding and apply it to drawer analysis intro 2026-05-21 16:41:40 +02:00
gitea_admin 4964ebfe08 Group analysis heading and status line into shared intro block 2026-05-21 16:36:11 +02:00
gitea_admin 749458e31a Move next earnings line below heading and update label text 2026-05-21 16:32:53 +02:00
gitea_admin 01e9f5b7df Move options row directly below drawer card and above next earnings text 2026-05-21 16:31:40 +02:00
gitea_admin 5c14b26a02 Add options row above analysis heading with mode toggle and small sandwich menu 2026-05-21 16:28:05 +02:00
gitea_admin ae0c146c87 Add white fundamental analysis heading above tab navigation 2026-05-21 16:26:03 +02:00
gitea_admin 0e5a4878d5 Add analysis delta text content to last-analysis comparison card 2026-05-21 16:24:35 +02:00
gitea_admin 420a9159d1 Wrap Gesamtbewertung cards in content-cards-group for spacing-small gap 2026-05-21 16:24:14 +02:00
gitea_admin 67156b8aa9 Add comparison card for last analysis date in Gesamtbewertung panel 2026-05-21 16:23:27 +02:00
gitea_admin e1a6a97f38 Set first Gesamtbewertung summary paragraph line to strong 2026-05-21 16:21:21 +02:00
gitea_admin 74b0deaf3d Add white summary segment text in Gesamtbewertung panel 2026-05-21 16:20:56 +02:00
gitea_admin 75ebbddcb5 Decouple gray card segment surface from card body token 2026-05-21 16:20:04 +02:00
gitea_admin ff1263fec4 Fix cascade order for VSF score segment gray background 2026-05-21 16:18:09 +02:00
gitea_admin ff9de2123c Force hellgrau background for VSF fundamental score segment 2026-05-21 16:17:06 +02:00
gitea_admin 0b719a48d1 Use dedicated gray card segment for single score bar in Gesamtbewertung 2026-05-21 16:16:04 +02:00
gitea_admin 185a208dba Add single-score bar component to Gesamtbewertung panel 2026-05-21 16:14:44 +02:00
gitea_admin a56a5e864a Remove extra spacing from full-width text layout pattern 2026-05-21 16:12:10 +02:00
gitea_admin 6a53ecd9c1 Add card group tab navigation with nine fundamental tabs to VSF drawer 2026-05-21 16:09:38 +02:00
gitea_admin 1832f3c3be Fix top spacing for next earnings line below VSF drawer card 2026-05-21 16:06:19 +02:00
gitea_admin 1b97bd1e32 Set next earnings text to white and add top spacing-large 2026-05-21 16:05:36 +02:00
gitea_admin 8177eae1af Move next earnings text line below VSF drawer card 2026-05-21 16:04:53 +02:00
gitea_admin ba05416711 Add next earnings full-width text line to VSF drawer actions 2026-05-21 16:04:04 +02:00
gitea_admin e38f5ac926 Toggle business model button label based on expanded state 2026-05-21 16:02:25 +02:00
gitea_admin 1563917df6 Restore full-width business model button in VSF drawer actions 2026-05-21 16:01:31 +02:00
gitea_admin 8a13580ede Ensure VSF drawer actions keep spacing-large after card segment base rules 2026-05-21 16:00:54 +02:00
gitea_admin b58aa91f0a Use spacing token gap between text block and button in VSF drawer actions 2026-05-21 16:00:13 +02:00
gitea_admin 2bd9e1df5b Fix drawer action segment flow so full-width text spacing applies 2026-05-21 15:58:14 +02:00
gitea_admin 3430203191 Add spacing-large bottom gap to full-width text layout pattern 2026-05-21 15:55:44 +02:00
gitea_admin 9fef090571 Add toggleable business model text block in VSF analysis drawer 2026-05-21 15:53:59 +02:00
gitea_admin b54c2f8e19 docs(foundations): add missing object-card-height token entry 2026-05-21 14:47:25 +02:00
gitea_admin 02a58a809d Update pulldown width token docs for content-based panel sizing 2026-05-21 14:45:54 +02:00
gitea_admin f4a54b0bb5 Adjust multiselect pulldown panel to content-based responsive width 2026-05-21 14:40:46 +02:00
gitea_admin be302d62a5 Increase object group card max width to 800px 2026-05-21 14:32:03 +02:00
gitea_admin 100b5422da Extract VSF drawer detail into standalone layout page 2026-05-21 12:02:17 +02:00
gitea_admin 2a58f9228b Rebuild VSF drawer card on base card pattern without object-card layout rules 2026-05-21 11:59:23 +02:00
gitea_admin 87556f8188 Fix VSF drawer card empty blue block by removing column flex-basis 100% 2026-05-21 11:57:29 +02:00
gitea_admin 6e823b9388 Remove fixed button height in VSF drawer final segment 2026-05-21 11:55:34 +02:00
gitea_admin 0f2e5809d2 Fix VSF drawer card residual segment by forcing auto height token and blue card surface 2026-05-21 11:54:15 +02:00
gitea_admin df71f91f3d Restore final blue drawer segment with normal business model button 2026-05-21 11:51:20 +02:00
gitea_admin dc3a815043 Collapse VSF drawer action segment to button-only final segment 2026-05-21 11:48:57 +02:00
gitea_admin 7725d74237 Remove content flex-grow on VSF drawer card to eliminate vertical gap 2026-05-21 11:47:13 +02:00
gitea_admin 3f309ebcdc Rename object card labels to card in cards component page 2026-05-21 11:45:41 +02:00
gitea_admin fbc4291da4 Add drawer card action segment and remove fixed height for VSF card 2026-05-21 11:44:46 +02:00
gitea_admin d650caf79c Make all cards on components cards page render full width 2026-05-21 11:41:16 +02:00
gitea_admin 4a0e4abef9 Force VSF drawer object card to full drawer width 2026-05-21 11:39:58 +02:00
gitea_admin 71a2932028 Replace two-column text pattern with deterministic 50-50 grid and update VSF drawer 2026-05-21 11:39:03 +02:00
gitea_admin fe2982a0d5 Fix VSF drawer text columns to exact left-right screenshot mapping 2026-05-21 11:38:16 +02:00
gitea_admin c4e14396fc Add VSF drawer object card with two-column white detail text 2026-05-21 11:35:23 +02:00
gitea_admin 6d91fccff1 Show text layout patterns on grey preview surface 2026-05-21 11:33:10 +02:00
gitea_admin 576357cf39 Add text layout patterns page with full, 60%, and two-column variants 2026-05-21 11:32:20 +02:00
gitea_admin bfd5e9cf66 Add VSF-specific mobile detail layout and wire redirect 2026-05-21 11:23:42 +02:00
gitea_admin df9d6ff2c0 Use exact company-card markup in VSF card list layout 2026-05-21 11:21:45 +02:00
gitea_admin 5fac475d82 Add VSF card list layout page with company cards 2026-05-21 11:20:03 +02:00
gitea_admin 97db864a3b Split layout sections into generic and Valuestockfinder 2026-05-21 11:13:53 +02:00
gitea_admin e817b60680 Fix drawer close on outside click on card list page 2026-05-21 11:07:06 +02:00
gitea_admin d5ad8d2d3c Set sg-body default bottom spacing to spacing-large 2026-05-21 10:23:19 +02:00
gitea_admin 3902f4f22d Adjust navigation card pattern vertical margin 2026-05-21 10:20:43 +02:00
gitea_admin 03d8e30a38 Fix sg-button link underline by resetting text decoration 2026-05-21 09:51:55 +02:00
gitea_admin ea94e2bd6a Set object group card min width to 550px 2026-05-21 09:29:27 +02:00
gitea_admin 097af6662e Add dedicated Object Group Card width tokens and rules 2026-05-21 09:07:55 +02:00
gitea_admin b0e1389f5f Apply company-card summary top spacing token with specific selector 2026-05-20 15:36:56 +02:00
gitea_admin ba8eb8ca85 Replace company-card inline styles with semantic tokens and classes 2026-05-20 15:35:54 +02:00
gitea_admin ff7baf0185 Add spacing-large gap between moat and summary text 2026-05-20 15:33:30 +02:00
gitea_admin b9c70f40b0 Add attractiveness and risk summary text to company card 2026-05-20 15:31:34 +02:00
gitea_admin 9b5e1fa265 Normalize moat spacing to match analysis block gap 2026-05-20 15:31:11 +02:00
gitea_admin 39fbe83d02 Add moat text below analysis score bars in company card 2026-05-20 15:30:12 +02:00
gitea_admin 6c3d3c3359 Tighten company-card analysis segment top spacing 2026-05-20 15:27:48 +02:00
gitea_admin c682cb615e Align score-bar labels and bars in shared list grid columns 2026-05-20 15:26:20 +02:00
gitea_admin 4c53d1c1b3 Make score-bar labels auto-size and remove local company-card override 2026-05-20 15:22:57 +02:00
gitea_admin 395d3fcaa2 Adjust company card score-bar label column width for long labels 2026-05-20 15:15:45 +02:00
gitea_admin 09c4e55cc3 Add fundamentalanalyse score bars to company card content segment 2026-05-20 15:14:23 +02:00
gitea_admin ff3c0c9498 Add data columns segment to company card using existing signal colors 2026-05-20 15:11:16 +02:00
gitea_admin 6e9edc33a9 Rename Gesamtscore-Balken label from pattern to component 2026-05-20 15:08:36 +02:00
gitea_admin 606e8d1c88 Fix company card score bar structure without list indentation 2026-05-20 15:07:17 +02:00
gitea_admin 4d34a183f4 Update company card title and add score bar segment 2026-05-20 15:06:12 +02:00
gitea_admin 7f7de8ad12 Add Company Card layout based on object card 2026-05-20 15:05:02 +02:00
gitea_admin eaf59c4ecc Remove company card layout and index entry 2026-05-20 14:16:34 +02:00
gitea_admin 1ea3b1e36f Adjust data columns to two numeric columns 2026-05-20 13:55:15 +02:00
gitea_admin 0f84c79b5e Replace single-score local chart overrides with semantic tokenized variants 2026-05-20 13:54:39 +02:00
gitea_admin e4304de9ce Add Data Columns component in data display 2026-05-20 13:52:31 +02:00
gitea_admin 2c822c7da0 Set single score pattern state label color to positive green 2026-05-20 13:46:17 +02:00
gitea_admin 20f2064289 Use bar-label typography for score state text in single score pattern 2026-05-20 13:45:30 +02:00
gitea_admin 47575e9687 Add right-aligned score state text to single score bar pattern 2026-05-20 13:43:49 +02:00
gitea_admin 99258a5881 Scope direct-after-label score bar alignment to single-score pattern only 2026-05-20 13:42:24 +02:00
gitea_admin 7d94446f88 Align score bars directly after label with large gap 2026-05-20 13:41:12 +02:00
gitea_admin 947c3d172e Use short score label in single score bar pattern to keep horizontal alignment 2026-05-20 13:40:18 +02:00
gitea_admin 1c526ad171 Add Gesamtscore-Balken pattern block below charts component 2026-05-20 13:39:23 +02:00
gitea_admin ab08919969 Increase score bar label-to-track spacing to large 2026-05-20 13:38:28 +02:00
gitea_admin dfb96f1838 Rename score bar labels to apples pears lemons in charts component 2026-05-20 13:37:46 +02:00
gitea_admin e8707e24e5 Set score bar remainder track to medium grey 2026-05-20 13:37:08 +02:00
gitea_admin c9112e5f2e Match charts preview surface width range to company card 2026-05-20 13:35:54 +02:00
gitea_admin 841020e102 Wrap charts component preview in padded light-grey surface 2026-05-20 13:34:49 +02:00
gitea_admin ad1bec8377 Adjust company card score row to horizontal label-bar-text layout 2026-05-20 13:33:13 +02:00
gitea_admin 421beed81b Add Company Card layout page based on existing object card and chart components 2026-05-20 13:31:34 +02:00
gitea_admin fece459f96 Raise pulldown overlay layer via centralized z-index token 2026-05-20 13:25:52 +02:00
gitea_admin 83c6b0289a Tokenize multiselect panel sizing and remove local viewport magic values 2026-05-20 13:20:11 +02:00
gitea_admin 25c7654534 Set multiselect panel width and clamp panel inside viewport 2026-05-20 13:16:57 +02:00
gitea_admin 674abc8ad6 Set multiselect pulldown width to 500px desktop and 80vw mobile 2026-05-20 13:15:14 +02:00
gitea_admin 48460ff0e0 Reserve mobile slider remove slot in pulldown rows 2026-05-19 20:21:43 +02:00
gitea_admin c5ddd32e17 Remove temporary test pulldown from multiselect pattern 2026-05-19 20:19:50 +02:00
gitea_admin 48e528b717 Stack pulldown field labels above controls on mobile 2026-05-19 20:18:50 +02:00
gitea_admin e18c8d999c Apply mobile stacked slider labels to all pulldown panels 2026-05-19 20:17:49 +02:00
gitea_admin 36f2b1a555 Stack test pulldown slider label above control on mobile 2026-05-19 20:16:16 +02:00
gitea_admin 8bd01223ae Use flex layout for mobile pulldown slider rows to avoid Safari grid issues 2026-05-19 19:55:56 +02:00
gitea_admin ac31b0d12c Harden slider rendering for iOS Safari WebKit 2026-05-19 19:52:26 +02:00
gitea_admin 3f9467f6eb Fix iPhone slider remove button style and row alignment in test pulldown 2026-05-19 19:48:35 +02:00
gitea_admin 104f5d771c Move test pulldown below multiselect options row as separate element 2026-05-19 19:43:57 +02:00
gitea_admin 4ace465f32 Add second multiselect pulldown variant with single activatable slider 2026-05-19 19:42:53 +02:00
gitea_admin adb4d7fd35 Revert "Fix mobile multiselect pulldown anchor width on small viewports"
This reverts commit 43c1702d53.
2026-05-19 19:41:45 +02:00
gitea_admin 43c1702d53 Fix mobile multiselect pulldown anchor width on small viewports 2026-05-19 19:41:24 +02:00
gitea_admin 704d7f708b Fix mobile multiselect pulldown panel width without :has dependency 2026-05-19 19:36:18 +02:00
gitea_admin d483650405 Revert "Fix mobile multiselect pulldown overflow and responsive row layouts"
This reverts commit 640b7fd4ad.
2026-05-19 19:31:27 +02:00
gitea_admin a1be888668 Revert "Harden mobile multiselect pulldown layout rules for narrow viewports"
This reverts commit 018e734df2.
2026-05-19 19:31:22 +02:00
gitea_admin 018e734df2 Harden mobile multiselect pulldown layout rules for narrow viewports 2026-05-19 19:29:21 +02:00
gitea_admin 640b7fd4ad Fix mobile multiselect pulldown overflow and responsive row layouts 2026-05-19 19:27:23 +02:00
gitea_admin 04a80804cb Activate inactive slider on direct thumb interaction 2026-05-19 16:32:20 +02:00
gitea_admin 150c0375e7 Align pulldown slider remove spacing with slider component 2026-05-19 16:13:52 +02:00
gitea_admin d490c1a179 Restore checkbox default unchecked interactive component state 2026-05-19 16:11:16 +02:00
gitea_admin 0b6a10cc74 Set multiselect checkbox to always-active state 2026-05-19 16:09:56 +02:00
gitea_admin 09791551b8 Restrict pulldown row activation to direct select interaction 2026-05-19 16:06:04 +02:00
gitea_admin f5e56f6c38 Add fourth block with three pulldown rows to multiselect pattern 2026-05-19 16:04:48 +02:00
gitea_admin 843f5de079 Ensure large spacing after multiselect block titles 2026-05-19 16:03:29 +02:00
gitea_admin b0a9b680e6 Add block-internal spacing rules for repeated vs mixed elements 2026-05-19 16:02:45 +02:00
gitea_admin 78fef1ba5f Fix desktop pulldown slider remove button overflow 2026-05-19 16:00:12 +02:00
gitea_admin 67ddc2e57a Normalize slider mobile wrap behavior and remove pattern-coupled overrides 2026-05-19 15:58:17 +02:00
gitea_admin bf34176f79 Apply global mobile slider wrap label-over-slider in pulldown panels 2026-05-19 15:55:44 +02:00
gitea_admin 6c8a58df54 Fix mobile multiselect pulldown slider line-break to match component 2026-05-19 15:54:52 +02:00
gitea_admin 5f29ce4641 Rebuild multiselect pulldown sliders from current slider component markup 2026-05-19 15:52:36 +02:00
gitea_admin 36e1682e64 Use inline remove button alignment for activatable slider 2026-05-19 15:49:40 +02:00
gitea_admin 9db4a50e68 Adjust desktop spacing for activatable slider remove button 2026-05-19 15:48:29 +02:00
gitea_admin f7b9f7c893 Align mobile activatable slider remove button with value 2026-05-19 15:47:30 +02:00
gitea_admin cca57b1dfe Fix mobile slider label spacing and value wrapping 2026-05-19 15:46:15 +02:00
gitea_admin 0895b8d24a Set multiselect pulldown trigger to always-active normal variant 2026-05-19 15:42:09 +02:00
gitea_admin cb79060f70 Add Multiselektions-Pulldown pattern with existing interactive components 2026-05-19 15:38:11 +02:00
gitea_admin 52a3c7e435 Revert "Add Multiselektionspulldown pattern based on form sections structure"
This reverts commit ba31de8870.
2026-05-19 15:27:10 +02:00
gitea_admin 4bc857ba64 Revert "Make Multiselektionspulldown fully interactive"
This reverts commit b81fd57e57.
2026-05-19 15:27:10 +02:00
72 changed files with 12990 additions and 3729 deletions
+9
View File
@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Write",
"Edit",
"Bash"
]
}
}
+94 -192
View File
@@ -1,235 +1,137 @@
---
name: styleguide erstellung
description: Verwenden für jede Weiterentwicklung des Styleguides. Erzwingt eine sauber kaskadierende, skalierbare Design-System-Architektur mit klarer Trennung von Foundations, semantischen Tokens, Components, Patterns, Layouts, Templates und Usage Guidelines. Nutze diesen Skill immer, wenn CSS, HTML, Tokens, Components, Patterns, Layouts, Templates, Dokumentation oder Styleguide-Strukturen geändert, erweitert oder geprüft werden.
name: styleguide-erstellung
description: Verwenden für Arbeiten am zentralen Styleguide: CSS, HTML, Foundation Tokens, semantische Tokens, Components, Patterns, Layouts, Templates, Pages, Doku oder Styleguide-Struktur. Erzwingt ein kaskadierendes, portalübergreifendes Design-System. Keine lokalen Styles, Insel-Tokens, Overrides, Workarounds, hardcoded Design Values, redundanten UI-Bausteine oder visuellen Nachbauten.
---
# Styleguide-Erstellung
## Ziel
Pflege und erweitere den Styleguide als skalierbares Design-System für große Webportale.
Den Styleguide als zentrales Design-System für mehrere Webportale pflegen.
Jede Änderung muss:
Zwingende Kaskade:
- sauber kaskadieren,
- der richtigen Styleguide-Ebene zugeordnet sein,
- bestehende Bausteine respektieren,
- langfristig wartbar und wiederverwendbar sein,
- zentral über Foundation Tokens und semantische Tokens in `styleguide.css` steuerbar bleiben,
- ohne lokale Sonderlösungen, visuelle Nachbauten oder Workarounds auskommen.
`Foundation Tokens → semantische Tokens → Components → Patterns → Layouts → Templates/Pages → Usage Guidelines`
## Verbindliche Struktur und Kaskade
Ergebnis muss clean, produktionsreif und frei von lokalen Insellösungen, Legacy-Resten und visuellen Nachbauten sein.
Der Styleguide wird nach dieser Kaskade entwickelt:
Downstream-Portale sollen Layout und Variation so weit wie möglich über CSS, semantische Tokens und vorhandene Bausteine lösen. HTML-Struktur nur ändern, wenn Semantik, Accessibility, Component-Grenzen oder fachliche Datenstruktur es erfordern.
```text
Foundations / Grundlagen
→ Semantische Tokens / Design Tokens
→ Components / Komponenten
→ Patterns / Muster
→ Layouts
→ Templates / Seitentemplates
→ Usage Guidelines / Anwendungsrichtlinien
```
## Token-Kaskade
Jede neue oder geänderte Lösung muss der passenden Ebene zugeordnet werden; Component- und Pattern-Kapitel dokumentieren dabei die semantischen Tokens, die dort verwendet werden.
- Foundation Tokens sind die einzige Quelle roher Designwerte: Farben, Typografie, Spacing, Radius, Shadows, Motion, Breakpoints, Z-Index, Containergrößen.
- Neue Foundation Tokens nur nach expliziter Freigabe; bestehende bevorzugt wiederverwenden.
- Semantische Tokens kontextualisieren Foundation Tokens für konkrete Verwendung, z. B. Component, Pattern, Layout oder Page.
- Semantische Tokens müssen immer auf Foundation Tokens verweisen; nie auf hardcoded Design Values.
- Components, Patterns, Layouts, Templates, Pages und HTML dürfen keine direkten Foundation-Token-Zugriffe, lokalen `:root`-Blöcke, Insel-Tokens oder hardcoded Design Values enthalten.
- Lokale Tokens sind nur erlaubt, wenn sie echte semantische Tokens der passenden Ebene sind, zentral in der zuständigen CSS-Datei gepflegt und über `styleguide.css` importiert werden.
Technische CSS-Werte ohne Designentscheidung sind erlaubt, z. B. `display`, `position`, `overflow`, `width: 100%`, `height: auto`, `flex`, `min-width: 0`.
## Core vs. Portal
- Core: Foundations, globale semantische Tokens, Components und generische Patterns.
- Portal-spezifisch: nur klar benannte Layouts, Templates oder Pages mit Portalname im Dateinamen.
- Portal-spezifische Dateien dürfen Core-Bausteine komponieren, aber nicht duplizieren, überschreiben oder visuell nachbauen.
- Wird eine portal-spezifische Lösung mehrfach relevant, in den Core abstrahieren.
- Fachlogik und Dateninterpretation gehören ins jeweilige Portal/Fachmodul, nicht in den Styleguide.
## Ebenenregeln
### Foundations
Foundations sind die einzige Quelle für konkrete visuelle Werte, z. B. Farben, Typografie, Spacing, Grid, Icons, Shadows, Border-Radius, Motion, Breakpoints, Z-Index und Containergrößen.
Neue oder geänderte Foundation-Werte nur nach Rückfrage und expliziter Freigabe einführen.
### Semantische Tokens / Design Tokens
Semantische Tokens abstrahieren Foundation Tokens nach Bedeutung, Zweck oder Verwendung im Interface und werden zentral in `styleguide.css` gepflegt.
Sie benennen nicht den konkreten visuellen Wert, sondern die Rolle im System, z. B. `surface-button-active`, `text-button-process` oder `layout-input-label-width`.
Regeln:
- Keine hardcoded Design Values außerhalb der Foundations.
- Semantische Tokens sind Aliase oder Kaskaden auf Foundation Tokens.
- Neue oder geänderte semantische Tokens an der fachlich passenden Stelle in `styleguide.css` ergänzen.
- Struktur, Reihenfolge, Gruppierung, Kommentarlogik und Benennungssystematik von `styleguide.css` einhalten.
- HTML-Dateien dürfen keine lokalen Token-Blöcke, keine eigenen `:root`-Definitionen und keine abweichenden Token-Definitionen enthalten.
- HTML-Dateien dürfen semantische Tokens nur aus `styleguide.css` referenzieren.
Ergänzungen semantischer Tokens dokumentieren mit:
- Token-Name
- Token-Typ: Foundation oder semantischer Token für Component, Pattern, Layout oder Template
- Wert oder Alias-Ziel
- kurzer Zweck
Wenn Foundation Tokens ergänzt oder geändert werden, `foundations.html` nachführen.
Wenn semantische Tokens für Components, Patterns, Layouts oder Templates ergänzt oder geändert werden, die passende Token-Dokumentation nachführen, insbesondere `semantic-tokens-components.html`, sofern dort die bestehende Struktur dafür vorgesehen ist.
### Components
Components sind kanonische, wiederverwendbare UI-Bausteine.
Component-Kapitel dokumentieren die semantischen Tokens, die eine Komponente verwendet, jeweils mit zugeordnetem Foundation Token und Verwendungszweck innerhalb der Komponente.
Ohne explizite Freigabe nicht erlaubt:
- Component-HTML verändern
- Component-Klassen verändern, ergänzen oder entfernen
- Component-Nesting verändern
- Component-Semantik verändern
- Component-Varianten erfinden
- Components visuell nachbauen
- Component-Internals von außen überschreiben
- Components sind kanonische UI-Bausteine.
- Ohne Freigabe keine Änderung an HTML, Klassen, Nesting, Semantik oder Varianten.
- Component-Internals nie von außen überschreiben.
- Components nie visuell nachbauen.
- Component-spezifische semantische Tokens in der zuständigen Component-Datei definieren; keine Insel-Tokens im Markup oder in Pages.
### Patterns
Patterns kombinieren bestehende Components für konkrete Anwendungsfälle.
- Patterns komponieren bestehende Components für wiederkehrende Anwendungsfälle.
- Erlaubt: Wrapper, Pattern-Klassen, Layout, Responsiveness.
- Verboten: Component-Optik duplizieren, Component-Internals stylen, Components ersetzen.
- Pattern-spezifische semantische Tokens nur für Pattern-Kontext definieren und aus Foundations ableiten.
- Wenn ein Pattern Component-Internals stylen müsste: stoppen und Component-Token, Variante oder Architekturentscheidung vorschlagen.
Pattern-Kapitel dokumentieren die semantischen Tokens, die ein Pattern verwendet, jeweils mit zugeordnetem Foundation Token und Verwendungszweck innerhalb des Patterns.
### Layouts, Templates und Pages
Erlaubt:
- Layouts regeln Struktur, Container, Raster, Anordnung und Responsiveness.
- Templates/Pages sind Komposition aus Layouts, Patterns und Components.
- Layout, Abstände und Varianten primär über CSS und semantische Tokens lösen, nicht über zusätzliche HTML-Struktur.
- HTML-Struktur nur für Semantik, Accessibility, Component-Grenzen oder fachliche Datenstruktur erweitern.
- Keine neuen Foundations, Component-Varianten, lokalen Styles, Insel-Tokens oder visuellen Regeln einführen.
- eigene Pattern-Klassen
- eigene Layout-/Wrapper-Strukturen
- Pattern-spezifische Responsiveness
- Pattern-spezifische Komposition
## CSS-Struktur
Nur erlaubt, wenn bestehende Components unverändert eingebettet werden.
- `styleguide.css` ist der einzige CSS-Einstiegspunkt. Jede neue/geänderte CSS-Datei muss dort importiert sein.
- Foundation Tokens nur in vorgesehenen Foundation-/Base-Dateien, insbesondere `01-foundations.css` und ggf. `02-base.css`.
- Semantische Tokens nur in zentralen Token-Bereichen oder in der zuständigen Component-/Pattern-/Layout-/Template-Datei.
- Components, Patterns, Layouts und Templates liegen in Dateien der passenden Ebene; keine Ebenen vermischen.
- Neue CSS-Dateien nur bei klar neuer Verantwortung; sonst bestehende Datei erweitern.
- Keine verwaisten oder unimportierten CSS-Dateien stehen lassen.
Verboten ohne Freigabe:
Import-Reihenfolge:
```css
.pattern .component-internal-class { ... }
.pattern .sg-card-segment { ... }
.pattern .sg-button__label { ... }
```
Wenn ein Pattern Component-Internals stylen müsste, nicht umsetzen. Rückfrage stellen und begründen, ob ein Component-Token, eine Component-Variante oder eine andere architektonische Lösung nötig ist.
### Layouts
Layouts regeln Struktur, Container, Raster und Anordnung.
Layouts dürfen Flächen strukturieren, Spalten und Container definieren, Abstände zwischen größeren Bereichen steuern und responsive Seitenanordnung regeln.
Layouts dürfen keine Component-Optik ersetzen, keine Pattern-Logik nachbauen, keine Component-Internals überschreiben und keine lokalen Designwerte einführen.
### Templates
Templates beschreiben wiederkehrende Seitentypen.
Templates verwenden bestehende Layouts, Patterns und Components. Sie dürfen keine neuen visuellen Grundlagen, Component-Varianten oder Pattern-Logiken erfinden.
### Usage Guidelines
Usage Guidelines dokumentieren die korrekte Verwendung des Systems.
Sie klären insbesondere:
- wann welches Pattern verwendet wird,
- responsive Verhalten,
- Accessibility,
- Dos & Donts,
- Abgrenzung ähnlicher Components, Patterns, Layouts oder Templates.
Guidelines müssen präzise, praxisnah und konsistent mit der bestehenden Styleguide-Struktur formuliert werden.
`Foundations/Base → globale semantische Tokens → Components → Patterns → allgemeine Layouts → portal-spezifische Layouts → allgemeine Templates/Pages → portal-spezifische Templates/Pages`
## Arbeitsablauf
Vor jeder Umsetzung:
Vor Umsetzung:
1. Task-Scope bestimmen.
2. Bestehenden Code und relevante Dokumentation im Scope analysieren.
3. Styleguide-Ebene der Änderung bestimmen.
4. Prüfen, ob bestehende Foundation Tokens, semantische Tokens, Components, Patterns, Layouts oder Templates verwendet werden können.
5. Offene oder nicht belegte Punkte klären.
1. Scope bestimmen.
2. Relevanten Code und Doku prüfen.
3. Richtige Ebene bestimmen.
4. Core oder portal-spezifisch entscheiden.
5. Bestehende Foundations, semantische Tokens, Components, Patterns, Layouts und Templates auf Wiederverwendung prüfen.
6. Prüfen, ob Layout per CSS statt zusätzlicher HTML-Struktur lösbar ist.
7. Betroffene Doku bestimmen.
8. Nicht belegte Punkte nicht umsetzen; bei Bedarf Rückfrage stellen.
Nicht umsetzen, solange eine notwendige Grundlage fehlt.
Wenn etwas nicht eindeutig im Code, in der Dokumentation oder in der Aufgabe belegt ist, Rückfrage stellen.
Aussagen bei Unsicherheit klassifizieren als: belegt, plausibel, nicht belegt.
## Scope und Grenzen
## Dokumentation
Keine Änderungen außerhalb des expliziten Task-Scopes.
Nachführen, wenn betroffen:
Nicht erlaubt ohne Freigabe:
- `index.html` bei neuen HTML-Seiten
- `foundations.html` bei Foundation-Änderungen
- Token-Doku bei semantischen Token-Änderungen
- betroffene Component-, Pattern-, Layout-, Template- oder Page-Doku
- bestehende Components umbauen
- Foundation Tokens oder semantische Tokens umbenennen
- Kaskade von Foundation Tokens zu semantischen Tokens verändern
- CSS-Struktur aufräumen
- HTML-Struktur verbessern, wenn nicht beauftragt
- neue Foundation-Werte einführen
- neue Component-Varianten erfinden
- bestehende Dokumentationsstruktur neu sortieren
## Verbote
Neue HTML-Seiten nur dann in `index.html` ergänzen, wenn tatsächlich neue Seiten angelegt werden. Bei reinen Änderungen bestehender Seiten ist keine `index.html`-Anpassung erforderlich.
Nie einführen oder stehen lassen:
## Anti-Insellösung
- lokale Styles, lokale `:root`-Blöcke oder lokale Token-Blöcke
- Insel-Tokens in Components, Patterns, Layouts, Templates, Pages oder HTML
- direkte Foundation-Token-Zugriffe außerhalb semantischer Token-Definitionen
- hardcoded Design Values außerhalb Foundations
- Overrides statt Ursachenbehebung
- Workarounds, Quickfixes oder Legacy-Fehlmuster
- visuelle Nachbauten bestehender Components/Patterns
- portal-spezifische Duplikate von Core-Bausteinen
- unnötige HTML-Wrapper nur für Optik/Layout
- unimportierte oder verwaiste CSS-Dateien
- Refactorings außerhalb Scope ohne Freigabe
Jede Lösung muss systemfähig sein.
## Abschluss
Verboten:
Vor Abschluss den bearbeiteten Scope aktiv bereinigen:
- lokale Styles zur Umgehung der Architektur
- seitenlokale Sonderregeln statt zentraler Foundation Tokens oder semantischer Tokens
- visuelle Nachbauten bestehender Components
- Workarounds, die Architekturdefizite verdecken
- Legacy-Fehlmuster kopieren
- direkte Designwerte in Components, Patterns, Layouts, Templates oder HTML-Dateien
- Insellösungen, Insel-Tokens, Overrides, Workarounds und Legacy-Reste entfernen.
- lokale Korrekturen auf die richtige Ebene zurückführen: Foundation Token, semantischer Token, Component, Pattern, Layout oder Template.
- Doku und `styleguide.css` aktualisieren.
- sicherstellen, dass Layout-Änderungen primär über CSS und semantische Tokens gelöst sind.
- erst fertig melden, wenn der Scope clean und produktionsreif ist.
Technische CSS-Werte sind erlaubt, wenn sie keine Designentscheidung darstellen, z. B.:
Kurz berichten:
```css
display: flex;
position: relative;
overflow: hidden;
min-width: 0;
width: 100%;
height: auto;
flex: 1 1 auto;
```
Wenn unklar ist, ob ein Wert eine Designentscheidung ist: Rückfrage stellen.
## Unsicherheiten
Bewerte relevante Aussagen als:
- **belegt**: direkt im Code oder in der Dokumentation nachweisbar
- **plausibel**: ableitbar, aber nicht eindeutig belegt
- **nicht belegt**: benötigt Rückfrage oder Freigabe
Nicht belegte Punkte dürfen nicht umgesetzt werden.
## Abschlusscheck
Vor Abschluss prüfen:
- richtige Styleguide-Ebene gewählt
- Kaskade Foundations → semantische Tokens → Components → Patterns → Layouts → Templates → Usage Guidelines eingehalten
- keine hardcoded Design Values außerhalb der Foundations
- neue oder geänderte semantische Tokens in `styleguide.css` gepflegt
- bestehende Struktur von `styleguide.css` eingehalten
- betroffene Dokumentation nachgeführt
- Components unverändert verwendet
- keine Component-Internals überschrieben
- Pattern-CSS steuert nur Komposition, Layout und Responsiveness
- Layout-CSS steuert nur Struktur und Anordnung
- Templates verwenden bestehende Layouts, Patterns und Components
- keine lokalen Token-Blöcke oder `:root`-Definitionen in HTML-Dateien
- keine Refactorings außerhalb Scope
- keine Insellösungen oder Workarounds eingeführt
## Ergebnisbericht
Nach Umsetzung kurz berichten:
- geänderte Dateien
- relevante geprüfte Dateien
- gewählte Styleguide-Ebene
- verwendete oder ergänzte Foundation Tokens und semantische Tokens
- verwendete Components, Patterns, Layouts oder Templates
- nachgeführte Dokumentation
- offene Punkte oder benötigte Freigaben
- geänderte/geprüfte Dateien
- gewählte Ebene und Core/Portal-Zuordnung
- verwendete oder ergänzte Foundation/semantische Tokens
- verwendete oder ergänzte Bausteine
- ob Layout per CSS statt Struktur gelöst wurde
- nachgeführte Doku
- entfernte Insellösungen/Workarounds
- offene Punkte oder nötige Freigaben
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

+26 -57
View File
@@ -1,65 +1,34 @@
# AGENTS.md
## Verbindliche Arbeitsweise
- Der Skill `styleguide erstellung` ist in diesem Projekt **immer** zu nutzen.
- Dieses Repository wird lokal bearbeitet und ist als Git-Repository mit Remote in Gitea geführt.
- Jede vom Agent umgesetzte Änderung wird direkt mit einer passenden Commit-Message committed und anschließend nach `origin/main` gepusht.
- Bei Änderungen an Foundation Tokens in `styleguide.css` muss `foundations.html` im selben Change-Set nachgeführt werden.
- Bei Änderungen an semantischen Component-/Pattern-/Layout-/Template-Tokens in `styleguide.css` muss `semantic-tokens-components.html` im selben Change-Set nachgeführt werden.
- Alle Arbeiten erfolgen ausschließlich innerhalb dieser Codebase:
- `/Users/mathias/Documents/Dokumente Chouchou/Codebases/Styleguide`
## Verbindliche Token-Policy (Merge vs. Behalten)
- Semantische Tokens dürfen denselben Foundation-Wert teilen, **wenn** sie unterschiedliche fachliche Bedeutung, unterschiedlichen UI-Kontext oder unterschiedliche Zustandssemantik ausdrücken.
- Semantische Tokens mit identischem Wert sind **zu mergen**, wenn sie:
- denselben Zweck haben,
- im selben UI-Kontext gelten,
- keinen eigenständigen fachlichen Namen benötigen.
- Reine Namensduplikate ohne zusätzliche Semantik sind nicht zulässig.
- Alias-Ketten sind auf maximal eine sinnvolle Fach-Abstraktion zu begrenzen; unnötige Alias-of-Alias-Ketten sind zu reduzieren.
- Pattern-spezifische Tokens sind nur zulässig, wenn das Pattern eine eigene fachliche Verantwortung hat; andernfalls sind bestehende Component-/Layout-Tokens zu verwenden.
- Sehr spezifische Einzelwerte (z. B. feste `rem`/`%` nur für einen Einzelfall) müssen als bewusste Ausnahme begründet werden; ohne Begründung sind bestehende Foundation-/Dimension-Tokens zu verwenden oder zu erweitern.
- Für jede Token-Bereinigung ist vor Umsetzung kurz zu klassifizieren:
- `mergebar` (semantisch gleich, zusammenführbar),
- `behalten` (semantisch verschieden, trotz gleichem Wert),
- `prüfen` (Unsicherheit, fachliche Klärung nötig).
- Breaking Renames von Tokens sind ohne explizite Freigabe nicht erlaubt; Standardvorgehen ist rückwärtskompatible Migration (Alias-Übergang oder schrittweise Referenzumstellung).
## Rolle des Agents
Du bist ein professioneller Interface Designer und Design-System-Architekt für große, skalierbare Webportale.
Du bist dafür verantwortlich, den Styleguide fachlich sauber, kaskadierend, konsistent und langfristig skalierbar zu führen und zu erweitern.
Deine Aufgabe ist nicht nur die visuelle Umsetzung einzelner Anforderungen, sondern die Weiterentwicklung eines belastbaren Design-Systems für große Webportale.
## Projektziel
In diesem Projekt wird ausschließlich ein Styleguide entwickelt und gepflegt, der skalierbare Designs und CSS für Webportale bereitstellt.
Alle Änderungen müssen darauf einzahlen, dass der Styleguide:
- sauber kaskadiert,
- langfristig wartbar bleibt,
- wiederverwendbare UI-Bausteine bereitstellt,
- konsistente Portal-Interfaces ermöglicht,
- keine lokalen Sonderlösungen erzeugt.
## Verhältnis zum Skill `styleguide erstellung`
Diese `AGENTS.md` definiert Rolle, Projektziel und Projektgrenze.
Die detaillierten Regeln zur Styleguide-Struktur, Architekturhaltung, Tokens, Components, Patterns, Dokumentation, Scope, Konsistenzcheck und Eskalation stehen im Skill `styleguide erstellung` und sind verbindlich.
Bei Konflikten gilt:
## Scope und Priorität
- Dieses Projekt pflegt ausschließlich den Styleguide für skalierbare Webportale.
- Alle Arbeiten erfolgen nur innerhalb dieser Codebase: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/Styleguide`.
- Keine Dateien außerhalb der Codebase lesen oder ändern.
- Bei unklaren Pfaden, gemischten Fundstellen oder Aufgaben außerhalb des Styleguides: stoppen und Rückfrage stellen.
- Konfliktreihenfolge:
1. Projektgrenze in dieser `AGENTS.md`
2. Skill `styleguide erstellung`
3. konkrete Nutzeraufgabe
## Projektgrenze
## Verbindliche Arbeitsweise
- Keine Dateien außerhalb dieser Codebase lesen oder ändern.
- Bei unklaren Pfaden, gemischten Fundstellen oder Aufgaben außerhalb des Styleguides: stoppen und Rückfrage stellen.
- Der Skill `styleguide erstellung` ist immer zwingend!!! zu nutzen und vollständig zu befolgen
- Lokaler Skill-Pfad: `/Users/mathias/Documents/Dokumente Chouchou/Codebases/Styleguide/.codex/skills/styleguide-erstellung/SKILL.md`.
- Repository ist lokal + Gitea-Remote geführt.
- Jede umgesetzte Änderung wird direkt mit passender Commit-Message committed und nach `origin/main` gepusht.
- Bei Änderungen an Foundation Tokens in `styleguide.css` muss `foundations.html` im selben Change-Set nachgeführt werden.
- Bei Änderungen an semantischen Component-/Pattern-/Layout-/Template-Tokens in `styleguide.css` muss `semantic-tokens-components.html` im selben Change-Set nachgeführt werden.
- CSS-Lesescope strikt eng halten:
- Nur die unmittelbar betroffenen CSS-Moduldateien lesen/ändern.
- `styleguide.css` nur für Import-Reihenfolge/Einbindung prüfen.
- Breitere CSS-Analyse nur nach expliziter Anforderung.
## Rolle und Zielbild
- Rolle: professioneller Interface Designer und Design-System-Architekt für große, skalierbare Webportale.
- Verantwortung: Styleguide fachlich sauber, kaskadierend, konsistent und langfristig skalierbar führen und erweitern.
- Ziel: wiederverwendbare UI-Bausteine, konsistente Portal-Interfaces, wartbare Struktur, keine lokalen Sonderlösungen.
## Minimalscope
Arbeite IMMER mit minimalem Lesescope: Lies nur die Dateien und Ausschnitte, die für die aktuelle Aufgabe zwingend nötig sind. Vermeide breite Codebase-Scans, unnötige Kontextsuche und grosse Dateiöffnungen, um Tokenverbrauch und Kontextgrösse klein zu halten. Auch kein breites Lesen in db Tabellen, lies Schemas und kleine Stichproben. Stelle gezielte Rückfragen, wenn der benötigte Kontext unklar ist.
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-hidden="true">
<path d="m12 2.8 2.89 5.85 6.46.94-4.68 4.56 1.1 6.44L12 17.53 6.23 20.59l1.1-6.44L2.65 9.59l6.46-.94L12 2.8Z" fill="#FFFFFF"/>
</svg>

After

Width:  |  Height:  |  Size: 228 B

+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-hidden="true">
<path d="m12 2.8 2.89 5.85 6.46.94-4.68 4.56 1.1 6.44L12 17.53 6.23 20.59l1.1-6.44L2.65 9.59l6.46-.94L12 2.8Z" fill="#000000"/>
</svg>

After

Width:  |  Height:  |  Size: 228 B

+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-hidden="true">
<path d="m12 2.8 2.89 5.85 6.46.94-4.68 4.56 1.1 6.44L12 17.53 6.23 20.59l1.1-6.44L2.65 9.59l6.46-.94L12 2.8Z" fill="none" stroke="#000000" stroke-width="1.6" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 285 B

+87 -8
View File
@@ -6,7 +6,7 @@
<title>Styleguide Cards</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<body class="sg-page-cards">
<h1 class="sg-main-heading">Components Cards</h1>
@@ -18,15 +18,15 @@
<!-- Components -->
<!-- ========================================================= -->
<!-- Component: Objekt Cards -->
<!-- Component: Cards -->
<section id="component-card">
<p class="sg-preview-label">Component: Objekt Cards</p>
<p class="sg-preview-label">Component: Cards</p>
<div class="sg-preview-area">
<article class="sg-card" data-component="card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Objekt Card 1</div>
<div class="sg-strong">Card 1</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
@@ -38,7 +38,7 @@
<article class="sg-card" data-component="card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen" data-component-part="card-header">
<div class="sg-strong">Objekt Card 2</div>
<div class="sg-strong">Card 2</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
@@ -50,7 +50,7 @@
<article class="sg-card" data-component="card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkbrown" data-component-part="card-header">
<div class="sg-strong">Objekt Card 3</div>
<div class="sg-strong">Card 3</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
@@ -63,6 +63,23 @@
</div>
</section>
<!-- Component: Basic Card -->
<section id="component-basic-card">
<p class="sg-preview-label">Component: Basic Card</p>
<div class="sg-preview-area">
<article class="sg-card" data-component="basic-card">
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body">
<p class="sg-body">
Basic Card mit nur einem Segment und hellgrauer Fläche gemäss Token.
</p>
</div>
</article>
</div>
</section>
<!-- Component: Content Card -->
<section id="component-content-card">
<p class="sg-preview-label">Component: Content Card</p>
@@ -84,11 +101,28 @@
</div>
</section>
<p class="sg-preview-label">Variante: Dark Content Card</p>
<div class="sg-preview-area">
<article class="sg-card sg-card--content-card sg-card--content-card-dark" data-component="content-card" aria-label="Dark Content Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__two-column" data-pattern-part="text-block-two-column">
<p class="sg-body sg-text-layout-pattern__column">
Footer links: Platzhaltertext fuer allgemeine Hinweise, Navigation oder Kontaktinformationen im zweispaltigen Layout.
</p>
<p class="sg-body sg-text-layout-pattern__column">
Footer rechts: Platzhaltertext fuer ergaenzende Angaben, rechtliche Hinweise oder sekundäre Footer-Inhalte im gleichen Raster.
</p>
</div>
</div>
</article>
</div>
<!-- Component: Group Card -->
<section id="component-group-card">
<p class="sg-preview-label">Component: Group Card</p>
<div class="sg-group-card" data-component="group-card">
<div class="sg-group-card sg-group-card--margin-after-large" data-component="group-card">
<article class="sg-card" data-component="card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
@@ -115,6 +149,51 @@
</article>
</div>
<p class="sg-preview-label">Variante: Group Card mit H2 Überschrift</p>
<div class="sg-group-card sg-group-card--margin-after-large" data-component="group-card">
<div class="sg-group-card__header-row">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading">Gruppenüberschrift</h2>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Gruppenmenü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Gruppenmenü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Gruppenüberschrift anpassen</a>
</div>
</div>
</div>
<article class="sg-card" data-component="card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Card in Group</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">
Group Cards bündeln mehrere zusammengehörige Cards.
</p>
</div>
</article>
<article class="sg-card" data-component="card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen" data-component-part="card-header">
<div class="sg-strong">Weitere Card</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">
Die Group Card enthält hier zusätzlich eine H2-Überschrift.
</p>
</div>
</article>
</div>
</section>
<!-- Component: Multisegment Card -->
@@ -156,7 +235,7 @@
<div class="sg-transparent-card" data-component="transparent-card">
<p class="sg-body">
Transparente Card ohne Padding.
Transparente Card mit standardisiertem Card-Padding.
</p>
</div>
+47 -3
View File
@@ -13,9 +13,10 @@
<section id="component-score-bar">
<p class="sg-preview-label">Component: Score-Balken / Median-Marker</p>
<div class="sg-form-preview-area sg-chart-preview-area">
<div class="sg-score-bar-list" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Label</p>
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Äpfel</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
@@ -23,7 +24,7 @@
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Label</p>
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Birnen</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
@@ -31,12 +32,55 @@
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Label</p>
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Zitronen</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker sg-score-bar__median-marker--outline" data-component-part="score-median-marker" data-component-variant="outline"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Kirschen</p>
<div class="sg-score-bar sg-score-bar--marker-mid sg-score-bar--no-value" role="img" aria-label="Keine Daten" data-component-part="score-track">
<span class="sg-score-bar__empty-state" data-component-part="score-empty-state">keine Daten</span>
</div>
</div>
</div>
</div>
</section>
<section id="pattern-gesamtscore-balken">
<p class="sg-preview-label">Component: Gesamtscore-Balken</p>
<div class="sg-form-preview-area sg-chart-preview-area">
<div class="sg-score-bar-list sg-score-bar-list--single-score" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="warning"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--warning" data-component-part="score-state">abwarten</p>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker sg-score-bar__median-marker--outline" data-component-part="score-median-marker" data-component-variant="outline"></div>
</div>
<p class="sg-bar-label sg-score-state--negative" data-component-part="score-state">unattraktiv</p>
</div>
</div>
</div>
</section>
+179
View File
@@ -48,5 +48,184 @@
</section>
<!-- Component: Data Columns -->
<section id="component-data-columns">
<p class="sg-preview-label">Component: Data Columns</p>
<table class="sg-data-table" aria-label="Beispiel Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td class="sg-data-table__value" data-component-part="data-columns-value-cell">7.7</td>
<td data-component-part="data-columns-reference-cell">11.7</td>
</tr>
<tr>
<td class="sg-data-table__value" data-component-part="data-columns-value-cell">8.6</td>
<td data-component-part="data-columns-reference-cell">9.7</td>
</tr>
<tr>
<td class="sg-data-table__value sg-data-table__value--warning" data-component-part="data-columns-value-cell" data-component-state="warning">1.23</td>
<td data-component-part="data-columns-reference-cell">1.43</td>
</tr>
</tbody>
</table>
</section>
<!-- Component: Large Table -->
<section id="component-large-table">
<p class="sg-preview-label">Component: Large Table</p>
<p>Suche, Sortierung und „Mehr laden“ sind hier Demo-Markup. Produktions-Implementierungen müssen Treffer serverseitig neu rendern.</p>
<article class="sg-card sg-large-table" data-component="large-table" role="table" aria-label="Beispiel Large Table">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-large-table__title-segment" data-component-part="large-table-header">
<div class="sg-strong">Large Table</div>
<span class="sg-search-field-row" data-component="search-field">
<span class="sg-input-single-line-wrap" data-has-value="false" data-component="single-line-input" data-component-state="inactive-selectable">
<input
class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
placeholder="Suche"
aria-label="Suchfeld ohne Eingabe"
data-large-table-search
>
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen">×</button>
</span>
</span>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row sg-large-table__row--header" role="row" data-component-part="large-table-header-row">
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="0">
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 1 sortieren">
<span class="sg-large-table__sort-label">Spalte 1</span>
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
</button>
</div>
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="1">
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 2 sortieren">
<span class="sg-large-table__sort-label">Spalte 2</span>
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
</button>
</div>
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="2">
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 3 sortieren">
<span class="sg-large-table__sort-label">Spalte 3</span>
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
</button>
</div>
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="3">
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 4 sortieren">
<span class="sg-large-table__sort-label">Spalte 4</span>
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
</button>
</div>
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="4">
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 5 sortieren">
<span class="sg-large-table__sort-label">Spalte 5</span>
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
</button>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A1</div>
<div class="sg-large-table__cell" role="cell">B1</div>
<div class="sg-large-table__cell" role="cell">C1</div>
<div class="sg-large-table__cell" role="cell">D1</div>
<div class="sg-large-table__cell" role="cell">E1</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A2</div>
<div class="sg-large-table__cell" role="cell">B2</div>
<div class="sg-large-table__cell" role="cell">C2</div>
<div class="sg-large-table__cell" role="cell">D2</div>
<div class="sg-large-table__cell" role="cell">E2</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A3</div>
<div class="sg-large-table__cell" role="cell">B3</div>
<div class="sg-large-table__cell" role="cell">C3</div>
<div class="sg-large-table__cell" role="cell">D3</div>
<div class="sg-large-table__cell" role="cell">E3</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A4</div>
<div class="sg-large-table__cell" role="cell">B4</div>
<div class="sg-large-table__cell" role="cell">C4</div>
<div class="sg-large-table__cell" role="cell">D4</div>
<div class="sg-large-table__cell" role="cell">E4</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A5</div>
<div class="sg-large-table__cell" role="cell">B5</div>
<div class="sg-large-table__cell" role="cell">C5</div>
<div class="sg-large-table__cell" role="cell">D5</div>
<div class="sg-large-table__cell" role="cell">E5</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A6</div>
<div class="sg-large-table__cell" role="cell">B6</div>
<div class="sg-large-table__cell" role="cell">C6</div>
<div class="sg-large-table__cell" role="cell">D6</div>
<div class="sg-large-table__cell" role="cell">E6</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A7</div>
<div class="sg-large-table__cell" role="cell">B7</div>
<div class="sg-large-table__cell" role="cell">C7</div>
<div class="sg-large-table__cell" role="cell">D7</div>
<div class="sg-large-table__cell" role="cell">E7</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A8</div>
<div class="sg-large-table__cell" role="cell">B8</div>
<div class="sg-large-table__cell" role="cell">C8</div>
<div class="sg-large-table__cell" role="cell">D8</div>
<div class="sg-large-table__cell" role="cell">E8</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A9</div>
<div class="sg-large-table__cell" role="cell">B9</div>
<div class="sg-large-table__cell" role="cell">C9</div>
<div class="sg-large-table__cell" role="cell">D9</div>
<div class="sg-large-table__cell" role="cell">E9</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
<div class="sg-large-table__cell" role="cell">A10</div>
<div class="sg-large-table__cell" role="cell">B10</div>
<div class="sg-large-table__cell" role="cell">C10</div>
<div class="sg-large-table__cell" role="cell">D10</div>
<div class="sg-large-table__cell" role="cell">E10</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row sg-large-table__row--load-more" role="row" data-component-part="large-table-row" data-large-table-load-more-row="true">
<div class="sg-large-table__cell sg-large-table__cell--load-more" role="cell">
<div class="sg-navigation-card-layout sg-large-table__load-more-layout">
<div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink" data-large-table-load-more-trigger="true">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</article>
</section>
</body>
</html>
File diff suppressed because it is too large Load Diff
+9 -10
View File
@@ -2,10 +2,16 @@
## Ziel
Der Styleguide bleibt in diesem Repository die Source of Truth. Das Portal holt:
Der Styleguide bleibt in diesem Repository die Source of Truth. Der Sync verteilt den freigegebenen Stand in beide Portal-Repos:
- den deploy-relevanten CSS-Upstream versioniert als `public/assets/styleguide.upstream.css`
- die vollstaendige Styleguide-Dokumentation gespiegelt nach `docs/styleguide`
- die portal-spezifische Fertig-CSS-Datei als `public/assets/styles.css`
Zielrepos:
- `WebApp_Aktienberater`
- `erp_naurua`
## Vorbereitung
@@ -21,19 +27,12 @@ Beispiel:
--commit-portal
```
Optional kann der Zielpfad ueberschrieben werden:
```bash
./scripts/sync_styleguide_to_webapp_aktienberater.sh \
--portal-repo "/absoluter/pfad/zum/portalrepo" \
--commit-portal
```
## Ergebnis im Portalrepo
- `public/assets/styleguide.upstream.css` aktualisiert
- `public/assets/styleguide.upstream.meta.json` aktualisiert (Version, Commit, Zeitstempel)
- `docs/styleguide` gespiegelt (mit `--delete`, ohne `.git`, `.codex`, `AGENTS.md`, `scripts/`)
- `public/assets/styles.css` aktualisiert
- Optional: automatischer Commit + Push im Portalrepo
## Standardprozess je Release
@@ -42,4 +41,4 @@ Optional kann der Zielpfad ueberschrieben werden:
2. `VERSION` erhoehen
3. Styleguide commit + push
4. Sync-Skript ausfuehren
5. Portal Smoke-Test
5. Beide Portalrepos Smoke-Testen
+34 -3
View File
@@ -27,6 +27,7 @@
<tr><td>light-grey</td><td>#E2E5E9</td><td>Card-Flächen, Card-Bodies, Formularflächen, Optionszeilen, inaktive Buttons, Sandwich-Menü-Flächen und Chart-/Score-Hintergründe.</td></tr>
<tr><td>medium-grey</td><td>#D4D6DB</td><td>Aktive Standardbuttons, geöffnete Pulldown-Flächen, Hilfetext-Flächen, Fragezeichen-Icons, Referenzwerte in Charts sowie Entfernen-Button in Eingabefeldern.</td></tr>
<tr><td>dark-grey</td><td>#7B879D</td><td>Ausgewählte Tab-Buttons als Fläche sowie Schriftfarbe für deaktivierte oder zurückgenommene Interaktionselemente.</td></tr>
<tr><td>black</td><td>#000000</td><td>Neutrale Vollton-Overlay-Farbe für starke visuelle Deaktivierung von Hintergrundobjekten.</td></tr>
<tr><td>white</td><td>#FFFFFF</td><td>Standardfläche von Buttons, Eingabefeldern, Pulldown-Triggern, Checkboxen, Radios, Toggle-Tracks und Card-Trennern.</td></tr>
<tr><td>signal-green</td><td>#009101</td><td>Positive Score-Balken und positive Chart-Werte.</td></tr>
<tr><td>signal-yellow</td><td>#9C7A00</td><td>Neutrale Score-Balken, neutrale Chart-Werte und Warnwerte in Tabellen.</td></tr>
@@ -76,8 +77,8 @@
<tbody>
<tr><td>body</td><td>Open Sans, 1rem, Regular</td><td>Standardtext im Portal.</td></tr>
<tr><td>brand</td><td>Open Sans, 1.6rem, Regular</td><td>Portal-Brand im Portal Header.</td></tr>
<tr><td>h1</td><td>Open Sans, 1.5rem, Regular</td><td>Hauptüberschriften; kleiner als Portal-Brand und 50% größer als Fließtext.</td></tr>
<tr><td>h2</td><td>Open Sans, 1.25rem, Regular</td><td>Zwischenüberschriften; kleiner als H1 und 25% größer als Fließtext.</td></tr>
<tr><td>h1</td><td>Open Sans, 1.8rem, Regular</td><td>Hauptüberschriften; kleiner als Portal-Brand und 80% größer als Fließtext.</td></tr>
<tr><td>h2</td><td>Open Sans, 1.5rem, Regular</td><td>Zwischenüberschriften; kleiner als H1 und 50% größer als Fließtext.</td></tr>
<tr><td>strong</td><td>Open Sans, 1rem, Semibold</td><td>Hervorgehobener Text, Labels und Button-Text.</td></tr>
<tr><td>section-title</td><td>Open Sans, 1rem, Regular</td><td>Section-Titel; aktuell identisch mit body, aber separat benannt.</td></tr>
<tr><td>bar-label</td><td>Open Sans, 1rem, Semibold</td><td>Labels bei Score-Balken.</td></tr>
@@ -87,6 +88,22 @@
</table>
</section>
<section id="foundations-portal-overrides">
<h2 class="sg-sub-heading sg-text-on-dark">Naurua Overrides</h2>
<table class="sg-foundation-table sg-table-label">
<thead>
<tr>
<th>Portal</th>
<th>Abweichung</th>
<th>Verwendung</th>
</tr>
</thead>
<tbody>
<tr><td>NAURUA</td><td>darkblue → #354A52; body → Avenir, sans-serif</td><td>Portalgebundene Foundation-Overrides für das zweite Portal. Die Überschreibung greift nur, wenn das Root-Element `data-portal="naurua"` setzt.</td></tr>
</tbody>
</table>
</section>
<section id="foundations-spacing">
<h2 class="sg-sub-heading sg-text-on-dark">Spacing</h2>
<table class="sg-foundation-table sg-table-label">
@@ -134,13 +151,27 @@
<tr><td>chart-axis-label-gap</td><td>5px</td><td>Horizontaler Abstand zwischen Y-Achsenbeschriftung und Y-Achse.</td></tr>
<tr><td>chart-grid-line-width</td><td>1px</td><td>Linienstärke von Gridlines und Achsen in Charts.</td></tr>
<tr><td>chart-line-width</td><td>2px</td><td>Linienstärke der Datenlinie im Line Chart.</td></tr>
<tr><td>input-label-width</td><td>9rem</td><td>Desktop-Breite der Label-Spalte bei ein- und mehrzeiligen Eingabefeldern.</td></tr>
<tr><td>input-label-width</td><td>9rem</td><td>Desktop-Breite der Label-Spalte für gruppierte Formularzeilen mit Pulldowns, Slidern, Radio-Feldern, Checkbox-Feldern sowie ein- und mehrzeiligen Eingabefeldern.</td></tr>
<tr><td>input-field-desktop-width</td><td>400px</td><td>Fixe Desktop-Breite von ein- und mehrzeiligen Eingabefeldern in der Input-Component-Preview.</td></tr>
<tr><td>input-field-max-width</td><td>600px</td><td>Maximale Breite von ein- und mehrzeiligen Eingabefeldern (ohne Suchfeld).</td></tr>
<tr><td>object-card-height</td><td>600px</td><td>Fixe Höhe der Object Card im Desktop-Layout (u. a. für Company Card).</td></tr>
<tr><td>content-card-margin-top-desktop</td><td>100px</td><td>Oberer Außenabstand der Content Card auf Desktop.</td></tr>
<tr><td>content-card-margin-top-mobile</td><td>1rem</td><td>Oberer Außenabstand der Content Card auf Mobile; entspricht spacing-large.</td></tr>
<tr><td>object-group-card-min-width</td><td>450px</td><td>Mindestbreite der Group Card im Pattern Object Group Card.</td></tr>
<tr><td>object-group-card-max-width</td><td>650px</td><td>Maximale Breite der Group Card im Pattern Object Group Card.</td></tr>
<tr><td>object-group-card-height</td><td>700px</td><td>Fixe Desktop-Höhe der Group Card im Pattern Object Group Card.</td></tr>
<tr><td>delete-confirmation-overlay-offset-block-start</td><td>10%</td><td>Vertikaler Abstand des Overlays vom oberen Rand des Zielobjekts, relativ zur Objektgröße.</td></tr>
<tr><td>delete-confirmation-overlay-max-height</td><td>calc(100vh - 10vh)</td><td>Maximalhöhe des Overlays relativ zum Viewport; danach scrollt der Inhalt innerhalb des Overlays.</td></tr>
<tr><td>notifications-card-min-width</td><td>445px</td><td>Mindestbreite der Notification Card im Pattern Notifications; 50px größer als die Object Card und Grundlage für Flex-Basis und Mindestbreite des Patterns.</td></tr>
<tr><td>search-field-width</td><td>15.3rem</td><td>Fixe Breite des Suchfeld-Inputs inklusive Clear-Button-Bereich.</td></tr>
<tr><td>layer-pulldown-panel</td><td>40</td><td>Layer-Stufe für geöffnete Pulldown-Ausklappfelder, damit sie über anderen Inhalten liegen.</td></tr>
<tr><td>multiselect-pulldown-panel-desktop-width</td><td>500px</td><td>Reservierte Foundation-Breite für Multiselektions-Pulldown-Panels; aktuell nicht aktiv genutzt, da das Panel inhaltsbasiert mit Viewport-Kappe skaliert.</td></tr>
<tr><td>multiselect-pulldown-panel-mobile-width</td><td>80vw</td><td>Reservierte mobile Foundation-Breite für Multiselektions-Pulldown-Panels; aktuell nicht aktiv genutzt, da das Panel inhaltsbasiert mit Viewport-Kappe skaliert.</td></tr>
<tr><td>options-row-mode-toggle-width</td><td>7rem</td><td>Breite des Modus-Schiebers in der Options Row.</td></tr>
<tr><td>options-row-help-panel-width</td><td>16rem</td><td>Breite des Help-Panels in der Options Row.</td></tr>
<tr><td>card-list-drawer-width</td><td>40%</td><td>Relative Breite des ausziehbaren Card-Listenbereichs.</td></tr>
<tr><td>notifications-text-segment-fixed-height</td><td>150px</td><td>Desktop-Höhe des ersten Text-Segments im Standard-Pattern Notifications.</td></tr>
<tr><td>notifications-text-segment-fixed-height-small</td><td>80px</td><td>Desktop-Höhe des ersten Text-Segments in der Variante Pattern Notifications small.</td></tr>
</tbody>
</table>
</section>
+22 -1
View File
@@ -40,24 +40,45 @@
<ul class="sg-index-list">
<li><a href="./patterns/portal-header.html">Portal Header</a></li>
<li><a href="./patterns/vsf-portal-header-public.html">VSF Portal Header Public</a></li>
<li><a href="./patterns/options-row.html">Options Row</a></li>
<li><a href="./patterns/object-card.html">Object Card</a></li>
<li><a href="./patterns/object-group-card.html">Object Group Card</a></li>
<li><a href="./patterns/navigation-card.html">Navigation Card</a></li>
<li><a href="./patterns/left-navigation.html">Left Navigation</a></li>
<li><a href="./patterns/notifications.html">Notifications</a></li>
<li><a href="./patterns/content-cards-group.html">Content Cards Group</a></li>
<li><a href="./patterns/multiselektionspulldown.html">Multiselektionspulldown</a></li>
<li><a href="./patterns/card-gruppe-mit-tastennavigation.html">Card Gruppe mit Tastennavigation</a></li>
<li><a href="./patterns/formular-mit-abschnitten.html">Formular mit Abschnitten</a></li>
<li><a href="./patterns/multiselektions-pulldown.html">Multiselektions-Pulldown</a></li>
<li><a href="./patterns/text-layouts.html">Text Layouts</a></li>
<li><a href="./patterns/delete-confirmation-overlay.html">Overlay Card</a></li>
</ul>
</section>
<section class="sg-index-section">
<h2 class="sg-sub-heading">Layouts</h2>
<h3 class="sg-sub-heading sg-section-h3">Generische Layouts</h3>
<ul class="sg-index-list">
<li><a href="./patterns/card-listen-seite.html">Card Listen Seite</a></li>
<li><a href="./patterns/page-layout-app.html">Page Layout App</a></li>
<li><a href="./patterns/page-layout-public.html">Page Layout Public</a></li>
<li><a href="./patterns/card-listen-fundamentalanalyse-mobile.html">Card Listen Fundamentalanalyse Mobile</a></li>
</ul>
<h3 class="sg-sub-heading sg-section-h3">Valuestockfinder Layouts</h3>
<ul class="sg-index-list">
<li><a href="./patterns/company-card.html">VSF Layout Company Card</a></li>
<li><a href="./patterns/vsf-list-card.html">VSF List Card</a></li>
<li><a href="./patterns/vsf-card-listen-seite.html">VSF Card Listen Seite</a></li>
<li><a href="./patterns/vsf-list-detailseite.html">VSF List Detailseite</a></li>
<li><a href="./patterns/vsf-meldungen.html">VSF Meldungen</a></li>
<li><a href="./patterns/vsf-register-step-1.html">VFS Keycloak Login</a></li>
<li><a href="./patterns/vsf-listen-uebersicht-seite-v2.html">VSF Listen Übersicht Seite V2</a></li>
<li><a href="./patterns/vsf-card-listen-fundamentalanalyse-mobile.html">VSF Card Listen Fundamentalanalyse Mobile</a></li>
<li><a href="./patterns/vsf-card-listen-fundamentalanalyse-drawer.html">VSF Card Listen Fundamentalanalyse Drawer</a></li>
</ul>
</section>
</main>
@@ -17,6 +17,10 @@
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" aria-controls="content-block-card-1" id="content-block-tab-1" data-component-part="tab-button">Taste 1</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="content-block-card-2" id="content-block-tab-2" data-component-part="tab-button">Taste 2</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="content-block-card-3" id="content-block-tab-3" data-component-part="tab-button">Taste 3</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="content-block-card-4" id="content-block-tab-4" data-component-part="tab-button">Taste 4</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="content-block-card-5" id="content-block-tab-5" data-component-part="tab-button">Taste 5</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="content-block-card-6" id="content-block-tab-6" data-component-part="tab-button">Taste 6</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="content-block-card-7" id="content-block-tab-7" data-component-part="tab-button">Taste 7</button>
</div>
<div class="sg-content-block-card-group__panels">
@@ -106,6 +110,58 @@
</article>
</div>
</div>
<div class="sg-content-block-card-group__panel" id="content-block-card-4" role="tabpanel" aria-labelledby="content-block-tab-4" hidden>
<div class="sg-content-cards-group" data-pattern="content-cards-group" aria-label="Card Gruppe Taste 4">
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Card 4.1">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Card 4.1</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Inhalt für Taste 4.</p>
</div>
</article>
</div>
</div>
<div class="sg-content-block-card-group__panel" id="content-block-card-5" role="tabpanel" aria-labelledby="content-block-tab-5" hidden>
<div class="sg-content-cards-group" data-pattern="content-cards-group" aria-label="Card Gruppe Taste 5">
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Card 5.1">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Card 5.1</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Inhalt für Taste 5.</p>
</div>
</article>
</div>
</div>
<div class="sg-content-block-card-group__panel" id="content-block-card-6" role="tabpanel" aria-labelledby="content-block-tab-6" hidden>
<div class="sg-content-cards-group" data-pattern="content-cards-group" aria-label="Card Gruppe Taste 6">
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Card 6.1">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Card 6.1</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Inhalt für Taste 6.</p>
</div>
</article>
</div>
</div>
<div class="sg-content-block-card-group__panel" id="content-block-card-7" role="tabpanel" aria-labelledby="content-block-tab-7" hidden>
<div class="sg-content-cards-group" data-pattern="content-cards-group" aria-label="Card Gruppe Taste 7">
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Card 7.1">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Card 7.1</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Inhalt für Taste 7.</p>
</div>
</article>
</div>
</div>
</div>
</div>
</section>
@@ -116,6 +172,38 @@
if (tabGroup) {
const tabs = Array.from(tabGroup.querySelectorAll('[role="tab"]'));
const panels = Array.from(tabGroup.querySelectorAll('[role="tabpanel"]'));
const tabList = tabGroup.querySelector('[role="tablist"]');
const applyMobileBalancedTabRows = () => {
if (!tabList) {
return;
}
tabs.forEach((tab) => {
tab.style.removeProperty('--sg-tab-mobile-row-slots');
});
if (window.matchMedia('(min-width: 768px)').matches || tabs.length <= 3) {
return;
}
const maxItemsPerRow = 3;
const rowCount = Math.ceil(tabs.length / maxItemsPerRow);
const baseRowSize = Math.floor(tabs.length / rowCount);
const rowRemainder = tabs.length % rowCount;
let tabStartIndex = 0;
for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
const rowSize = baseRowSize + (rowIndex < rowRemainder ? 1 : 0);
for (let itemOffset = 0; itemOffset < rowSize; itemOffset += 1) {
const tab = tabs[tabStartIndex + itemOffset];
if (tab) {
tab.style.setProperty('--sg-tab-mobile-row-slots', String(rowSize));
}
}
tabStartIndex += rowSize;
}
};
const activateTab = (targetTab) => {
tabs.forEach((tab) => {
@@ -145,6 +233,9 @@
activateTab(nextTab);
});
});
applyMobileBalancedTabRows();
window.addEventListener('resize', applyMobileBalancedTabRows);
}
</script>
+81 -140
View File
@@ -25,8 +25,8 @@
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link sg-body" href="#" data-component-part="sandwich-menu-link">Logout</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
@@ -100,22 +100,11 @@
</div>
</div>
<div class="sg-card-list-page__title-row">
<h1 class="sg-heading-h1 sg-text-on-dark sg-card-list-page__title">Listenübersicht</h1>
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="layout-card-list-page">
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext zur Listenübersicht anzeigen" data-component-part="help-trigger">?</button>
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
Hilfe zur Listenansicht und zu den Filteroptionen.
</span>
</span>
<div class="sg-transparent-card sg-card-list-page__intro-block" aria-label="Einleitung zur Listenübersicht" data-component="transparent-card">
<h1 class="sg-heading-h1 sg-text-on-dark">Listenübersicht</h1>
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--sixty-width">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer convallis purus sed urna ultricies, id aliquet justo malesuada. Morbi luctus, augue in cursus ultrices, justo lorem posuere mi, at suscipit est turpis vitae ipsum. Praesent posuere nisl a nisl fermentum, nec feugiat odio volutpat. Nam id dictum justo, eget dapibus arcu. Fusce varius justo nec nibh gravida, sed dignissim est tempor.</p>
</div>
<article class="sg-card sg-transparent-card sg-card-list-page__intro-card" aria-label="Einleitung zur Listenübersicht">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer convallis purus sed urna ultricies, id aliquet justo malesuada. Morbi luctus, augue in cursus ultrices, justo lorem posuere mi, at suscipit est turpis vitae ipsum. Praesent posuere nisl a nisl fermentum, nec feugiat odio volutpat. Nam id dictum justo, eget dapibus arcu. Fusce varius justo nec nibh gravida, sed dignissim est tempor.</p>
</div>
</article>
<div class="sg-object-card-grid sg-card-list-page__object-grid" aria-label="Objektliste">
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card 1">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
@@ -129,9 +118,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -157,9 +146,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -185,9 +174,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -213,9 +202,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -241,9 +230,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -269,9 +258,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -297,9 +286,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -325,9 +314,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -353,9 +342,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -381,9 +370,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -409,9 +398,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -437,9 +426,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -465,9 +454,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -493,9 +482,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -521,9 +510,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -549,9 +538,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -577,9 +566,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -605,9 +594,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -633,9 +622,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -661,9 +650,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -749,6 +738,7 @@
</div>
</aside>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
const updateObjectCardGridRowState = () => {
document.querySelectorAll('.sg-object-card-grid').forEach((grid) => {
@@ -881,14 +871,6 @@
}
});
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
@@ -934,53 +916,9 @@
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
if (!button || !panel) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-help-icon-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-help-icon');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.align = 'left';
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
wrap.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
@@ -1025,6 +963,8 @@
return;
}
button.dataset.drawerOpenTrigger = 'true';
button.addEventListener('click', () => {
if (mobileBreakpoint.matches) {
window.location.href = './card-listen-fundamentalanalyse-mobile.html';
@@ -1048,6 +988,15 @@
});
document.addEventListener('click', (event) => {
if (
fundamentalDrawer &&
fundamentalDrawer.dataset.open === 'true' &&
!event.target.closest('.sg-card-list-page-drawer') &&
!event.target.closest('[data-drawer-open-trigger="true"]')
) {
setFundamentalDrawerState(false);
}
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
@@ -1058,15 +1007,7 @@
});
}
if (!event.target.closest('.sg-help-icon-wrap') && !event.target.closest('.sg-pulldown-demo')) {
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
if (!event.target.closest('.sg-pulldown-demo')) {
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
+165
View File
@@ -0,0 +1,165 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF Layout Company Card</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">VSF Layout Company Card</h1>
<section id="layout-company-card">
<p class="sg-preview-label">Layout: Company Card</p>
<p class="sg-body">Dieses Layout basiert auf der Object Card und zeigt initial eine einzelne Company Card Instanz.</p>
<div class="sg-object-card-grid">
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-company-card__header-title">
<div class="sg-strong">Netflix, Inc.</div>
<span class="sg-company-card__header-star" aria-hidden="true"></span>
</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__three-column-distributed" aria-label="Company Kennzahlen dreispaltig verteilt" data-pattern-part="company-card-metrics-three-column">
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-left">
PE: <span class="sg-data-table__value">28.8</span>
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-center">
PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span>
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-right">
PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span>
</p>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
</div>
</section>
<script>
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
const panel = wrap.querySelector('.sg-sandwich-menu-panel');
if (!button) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState || !panel) {
return;
}
wrap.dataset.align = 'right';
const panelRect = panel.getBoundingClientRect();
if (panelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
});
document.addEventListener('click', (event) => {
if (event.target.closest('.sg-sandwich-menu-wrap')) {
return;
}
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
});
</script>
</body>
</html>
+521
View File
@@ -0,0 +1,521 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern Overlay Card</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern - Overlay Card</h1>
<section id="pattern-overlay-card" class="sg-delete-confirmation-pattern">
<p class="sg-preview-label">Pattern: Overlay Card</p>
<div class="sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-object-card" data-pattern="overlay-card" data-dialog-open="false" data-overlay-confirmation-value="DELETE">
<article class="sg-card sg-object-card sg-delete-confirmation-pattern__target" aria-label="Zu löschendes Objekt">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header">
<div class="sg-strong">Alcon Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#!" data-overlay-open-dialog="delete">Objekt löschen</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content">
<p class="sg-body">Objekt-Inhalt der Card. Während das Löschfenster sichtbar ist, wird dieses Objekt um 50% ausgegraut.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Löschbestätigung" role="dialog" aria-modal="true" aria-labelledby="delete-confirmation-title" data-overlay-dialog="delete" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="delete-confirmation-title"><strong>Möchtest du Alcon Inc. wirklich löschen?</strong></p>
<p class="sg-body sg-delete-confirmation-pattern__text">Du kannst das nicht rückgängig machen. Bestätige durch Eingabe von <span class="sg-delete-confirmation-pattern__code">DELETE</span>.</p>
<label class="sg-labeled-input-row sg-delete-confirmation-pattern__input-row">
<span class="sg-label">Bestätigung</span>
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
placeholder="DELETE"
aria-label="Löschbestätigung durch DELETE"
data-overlay-confirmation-input
>
</label>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button
class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive"
type="button"
disabled
aria-disabled="true"
data-overlay-confirmation-submit
data-overlay-dialog-close
>
Löschen
</button>
</div>
</div>
</article>
</div>
</section>
<section id="pattern-add-to-list-overlay" class="sg-delete-confirmation-pattern">
<p class="sg-preview-label">Pattern: Add to List Overlay</p>
<div class="sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-object-card" data-pattern="add-to-list-overlay" data-dialog-open="false" data-overlay-selected-lists="1,2">
<article class="sg-card sg-object-card sg-delete-confirmation-pattern__target" aria-label="Zu einer Liste hinzuzufügendes Objekt">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header">
<div class="sg-strong">Alcon Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Zur Liste hinzufügen" data-component-part="sandwich-trigger" data-overlay-open-dialog="add-to-list">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content">
<p class="sg-body">Objekt-Inhalt der Card. Während das Overlay sichtbar ist, wird dieses Objekt um 50% ausgegraut.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-card--overlay-host sg-object-card sg-object-card--variable-height sg-delete-confirmation-pattern__floating-card" aria-label="Zur Liste hinzufügen" role="dialog" aria-modal="true" aria-labelledby="add-to-list-title" data-overlay-dialog="add-to-list" hidden>
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header">
<p class="sg-body sg-strong" id="add-to-list-title">Füge das Unternehmen einer Liste hinzu</p>
</header>
<div class="sg-delete-confirmation-pattern__scroll-region">
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<ul class="sg-delete-confirmation-pattern__list" aria-label="Listen">
<li class="sg-delete-confirmation-pattern__list-item">
<button class="sg-interaction-element sg-button sg-delete-confirmation-pattern__list-button" type="button" data-overlay-list-toggle data-overlay-list-id="1" aria-pressed="true">
<span class="sg-delete-confirmation-pattern__list-icon" aria-hidden="true"></span>
<span class="sg-delete-confirmation-pattern__list-label">Liste 1</span>
</button>
</li>
<li class="sg-delete-confirmation-pattern__list-item">
<button class="sg-interaction-element sg-button sg-delete-confirmation-pattern__list-button" type="button" data-overlay-list-toggle data-overlay-list-id="2" aria-pressed="true">
<span class="sg-delete-confirmation-pattern__list-icon" aria-hidden="true"></span>
<span class="sg-delete-confirmation-pattern__list-label">Liste 2</span>
</button>
</li>
<li class="sg-delete-confirmation-pattern__list-item">
<button class="sg-interaction-element sg-button sg-delete-confirmation-pattern__list-button" type="button" data-overlay-list-toggle data-overlay-list-id="3" aria-pressed="false">
<span class="sg-delete-confirmation-pattern__list-icon" aria-hidden="true"></span>
<span class="sg-delete-confirmation-pattern__list-label">Liste 3</span>
</button>
</li>
<li class="sg-delete-confirmation-pattern__list-item">
<button class="sg-interaction-element sg-button sg-delete-confirmation-pattern__list-button" type="button" data-overlay-list-toggle data-overlay-list-id="4" aria-pressed="false">
<span class="sg-delete-confirmation-pattern__list-icon" aria-hidden="true"></span>
<span class="sg-delete-confirmation-pattern__list-label">Liste 4</span>
</button>
</li>
<li class="sg-delete-confirmation-pattern__list-item">
<button class="sg-interaction-element sg-button sg-delete-confirmation-pattern__list-button" type="button" data-overlay-list-toggle data-overlay-list-id="5" aria-pressed="false">
<span class="sg-delete-confirmation-pattern__list-icon" aria-hidden="true"></span>
<span class="sg-delete-confirmation-pattern__list-label">Liste 5</span>
</button>
</li>
</ul>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-delete-confirmation-pattern__create-list-toggle" type="button" data-create-list-form-toggle aria-expanded="false">Neue Liste anlegen</button>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body sg-delete-confirmation-pattern__create-list-segment" data-create-list-form hidden>
<p class="sg-body sg-delete-confirmation-pattern__text sg-delete-confirmation-pattern__create-list-title" data-create-list-title>Füge das Unternehmen einer neuen Liste hinzu</p>
<div class="sg-form-sections-card-wrapper sg-delete-confirmation-pattern__create-list-form" aria-label="Formular mit Abschnitten">
<form class="sg-form-sections-card" action="#" method="post" aria-label="Neue Liste anlegen Formular">
<div class="sg-form-sections-card__body" data-pattern-part="form-body">
<section class="sg-form-sections-card__chapter" aria-label="Neue Liste">
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Name</span>
<span class="sg-input-validation-stack">
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
placeholder="Name eingeben"
aria-label="Name"
maxlength="80"
aria-describedby="create-list-name-error"
>
<span class="sg-form-validation-text" id="create-list-name-error" hidden>Eine Liste mit diesem Namen existiert bereits.</span>
</span>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Beschreibung</span>
<textarea
class="sg-input-multi-line sg-form-inactive-selectable"
rows="4"
placeholder="Beschreibung eingeben"
aria-label="Beschreibung"
maxlength="350"
></textarea>
</label>
</div>
</section>
</div>
</form>
</div>
</div>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__actions-segment">
<div class="sg-delete-confirmation-pattern__actions sg-delete-confirmation-pattern__actions--footer">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-cancel>Abbrechen</button>
<button class="sg-interaction-element sg-button sg-button--process" type="button" data-overlay-dialog-save>Speichern</button>
</div>
</footer>
</article>
</div>
</section>
<script>
const setupOverlayStage = (stage) => {
const confirmationInput = stage.querySelector('[data-overlay-confirmation-input]');
const confirmationSubmitButton = stage.querySelector('[data-overlay-confirmation-submit]');
const expectedConfirmationValue = stage.dataset.overlayConfirmationValue ?? '';
const overlayListButtons = Array.from(stage.querySelectorAll('[data-overlay-list-toggle]'));
const overlayList = stage.querySelector('.sg-delete-confirmation-pattern__list');
const createListForm = stage.querySelector('[data-create-list-form]');
const createListFormToggle = stage.querySelector('[data-create-list-form-toggle]');
const createListTitle = stage.querySelector('[data-create-list-title]');
const createListSegment = stage.querySelector('[data-create-list-form]');
const createListNameInput = stage.querySelector('[data-create-list-form] input[aria-label="Name"]');
const createListNameError = stage.querySelector('#create-list-name-error');
const createListDescriptionInput = stage.querySelector('[data-create-list-form] textarea[aria-label="Beschreibung"]');
const isAddToListOverlay = stage.dataset.pattern === 'add-to-list-overlay';
const committedListIds = new Set(
(stage.dataset.overlaySelectedLists ?? '')
.split(',')
.map((value) => value.trim())
.filter(Boolean)
);
let draftListIds = new Set(committedListIds);
let resetAddToListDraftState = () => {};
const updateFloatingCardHeight = (dialog) => {
const stageHeight = stage.getBoundingClientRect().height;
const floatingCardHeight = Math.max(0, Math.round(stageHeight * 0.9));
dialog.style.setProperty('--layout-delete-confirmation-overlay-height', `${floatingCardHeight}px`);
};
const closeStageDialogs = ({ resetAddToListDraft = false } = {}) => {
stage.querySelectorAll('[data-overlay-dialog]').forEach((dialog) => {
dialog.hidden = true;
});
if (isAddToListOverlay && resetAddToListDraft) {
resetAddToListDraftState();
}
stage.dataset.dialogOpen = 'false';
};
const syncOverlayListState = () => {
overlayListButtons.forEach((button) => {
const listId = button.dataset.overlayListId;
const isSelected = Boolean(listId && draftListIds.has(listId));
button.dataset.selected = String(isSelected);
button.setAttribute('aria-pressed', String(isSelected));
});
};
const bindOverlayListButton = (button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
const listId = button.dataset.overlayListId;
if (!listId) {
return;
}
if (draftListIds.has(listId)) {
draftListIds.delete(listId);
} else {
draftListIds.add(listId);
}
syncOverlayListState();
});
};
const appendCreatedListButton = (title) => {
if (!overlayList) {
return null;
}
const listId = `created-${Date.now()}`;
const listItem = document.createElement('li');
listItem.className = 'sg-delete-confirmation-pattern__list-item';
const button = document.createElement('button');
button.type = 'button';
button.className = 'sg-interaction-element sg-button sg-delete-confirmation-pattern__list-button';
button.dataset.overlayListToggle = '';
button.dataset.overlayListId = listId;
button.dataset.selected = 'true';
button.setAttribute('aria-pressed', 'true');
const icon = document.createElement('span');
icon.className = 'sg-delete-confirmation-pattern__list-icon';
icon.setAttribute('aria-hidden', 'true');
const label = document.createElement('span');
label.className = 'sg-delete-confirmation-pattern__list-label';
label.textContent = title;
button.append(icon, label);
listItem.appendChild(button);
overlayList.appendChild(listItem);
overlayListButtons.push(button);
bindOverlayListButton(button);
return listId;
};
const setCreateListNameErrorState = (isInvalid) => {
if (!createListNameInput || !createListNameError) {
return;
}
createListNameInput.setAttribute('aria-invalid', String(isInvalid));
createListNameError.hidden = !isInvalid;
if (!isInvalid) {
createListNameInput.removeAttribute('aria-describedby');
} else {
createListNameInput.setAttribute('aria-describedby', 'create-list-name-error');
}
};
if (confirmationInput && confirmationSubmitButton) {
const updateConfirmationState = () => {
const isValid = confirmationInput.value === expectedConfirmationValue;
confirmationSubmitButton.disabled = !isValid;
confirmationSubmitButton.setAttribute('aria-disabled', String(!isValid));
confirmationSubmitButton.classList.toggle('sg-button--process-inactive', !isValid);
};
confirmationInput.addEventListener('input', updateConfirmationState);
updateConfirmationState();
}
if (overlayListButtons.length > 0) {
syncOverlayListState();
}
if (createListForm && createListFormToggle) {
resetAddToListDraftState = () => {
draftListIds = new Set(committedListIds);
syncOverlayListState();
setCreateListNameErrorState(false);
if (createListSegment) {
createListSegment.hidden = true;
}
if (createListFormToggle) {
createListFormToggle.disabled = false;
createListFormToggle.setAttribute('aria-disabled', 'false');
createListFormToggle.setAttribute('aria-expanded', 'false');
createListFormToggle.classList.remove('sg-button--inactive');
createListFormToggle.classList.add('sg-button--active');
}
if (createListNameInput) {
createListNameInput.value = '';
}
if (createListDescriptionInput) {
createListDescriptionInput.value = '';
}
};
createListFormToggle.addEventListener('click', (event) => {
event.preventDefault();
setCreateListNameErrorState(false);
if (createListSegment) {
createListSegment.hidden = false;
}
createListFormToggle.setAttribute('aria-expanded', 'true');
createListFormToggle.classList.remove('sg-button--active');
createListFormToggle.classList.add('sg-button--inactive');
createListFormToggle.disabled = true;
createListFormToggle.setAttribute('aria-disabled', 'true');
});
}
if (isAddToListOverlay) {
resetAddToListDraftState();
}
closeStageDialogs({ resetAddToListDraft: false });
stage.querySelectorAll('[data-overlay-open-dialog]').forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
const target = link.getAttribute('data-overlay-open-dialog');
const dialog = stage.querySelector(`[data-overlay-dialog="${target}"]`);
if (!dialog) {
return;
}
closeStageDialogs({ resetAddToListDraft: target === 'add-to-list' });
dialog.hidden = false;
updateFloatingCardHeight(dialog);
stage.dataset.dialogOpen = 'true';
const menuWrap = link.closest('.sg-sandwich-menu-wrap');
const menuButton = menuWrap?.querySelector('.sg-sandwich-button');
if (menuWrap) {
menuWrap.dataset.open = 'false';
}
if (menuButton) {
menuButton.setAttribute('aria-expanded', 'false');
}
});
});
stage.querySelectorAll('[data-overlay-dialog-close]').forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
closeStageDialogs();
});
});
stage.querySelectorAll('[data-overlay-dialog-cancel]').forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
closeStageDialogs({ resetAddToListDraft: true });
});
});
stage.querySelectorAll('[data-overlay-dialog-save]').forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
if (isAddToListOverlay) {
const createdListTitle = createListNameInput?.value.trim() ?? '';
const existingListNames = new Set(
Array.from(stage.querySelectorAll('.sg-delete-confirmation-pattern__list-label'))
.map((label) => label.textContent?.trim().toLowerCase())
.filter(Boolean)
);
if (!createdListTitle) {
setCreateListNameErrorState(true);
return;
}
if (existingListNames.has(createdListTitle.toLowerCase())) {
setCreateListNameErrorState(true);
return;
}
setCreateListNameErrorState(false);
if (createdListTitle) {
const createdListId = appendCreatedListButton(createdListTitle);
if (createdListId) {
draftListIds.add(createdListId);
committedListIds.add(createdListId);
}
}
committedListIds.clear();
draftListIds.forEach((value) => committedListIds.add(value));
stage.dataset.overlaySelectedLists = Array.from(committedListIds).join(',');
}
closeStageDialogs({ resetAddToListDraft: true });
});
});
stage.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
const panel = wrap.querySelector('.sg-sandwich-menu-panel');
if (!button) {
return;
}
if (button.hasAttribute('data-overlay-open-dialog')) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState || !panel) {
return;
}
wrap.dataset.align = 'right';
const panelRect = panel.getBoundingClientRect();
if (panelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
});
return closeStageDialogs;
};
const overlayStages = Array.from(document.querySelectorAll('.sg-delete-confirmation-pattern__stage'));
overlayStages.forEach((stage) => {
setupOverlayStage(stage);
});
document.addEventListener('click', (event) => {
if (event.target.closest('.sg-sandwich-menu-wrap')) {
return;
}
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
});
</script>
</body>
</html>
+160
View File
@@ -0,0 +1,160 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern Left Navigation</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern Left Navigation</h1>
<section id="pattern-left-navigation" class="sg-left-navigation-pattern">
<p class="sg-preview-label">Pattern: Left Navigation</p>
<p class="sg-body">
Die linke Navigationsspalte nutzt auf Desktop 15% der verfügbaren Breite. Die zweite Group Card ist leer und dient in der Demo nur dazu, den restlichen Bildschirm zu füllen.
</p>
<div class="sg-left-navigation-pattern__layout" aria-label="Left Navigation Demo">
<aside class="sg-group-card sg-left-navigation-pattern__group-card sg-left-navigation-pattern__group-card--navigation" data-component="group-card" aria-label="Linke Navigation">
<div class="sg-group-card__header-row sg-left-navigation-pattern__header-row">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading">Navigation</h2>
<button
class="sg-interaction-element sg-button sg-button--active sg-left-navigation-pattern__toggle"
type="button"
data-left-navigation-toggle
aria-expanded="true"
aria-controls="left-navigation-menu"
>
Ausblenden
</button>
</div>
<nav class="sg-tab-button-group" id="left-navigation-menu" role="tablist" aria-label="Linksmenue Items" data-component="tab-navigation" data-component-size="large" data-component-variant="linksmenu-items">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" data-component-part="tab-button">Übersicht</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Unternehmen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Kennzahlen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Nachrichten</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Einstellungen</button>
</nav>
</aside>
<section class="sg-group-card sg-left-navigation-pattern__group-card sg-left-navigation-pattern__group-card--content" data-component="group-card">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" data-left-navigation-content-heading>Übersicht</h2>
<p class="sg-body sg-left-navigation-pattern__content-text">
Zeile 1: Überblick über die aktuelle Navigation.<br>
Zeile 2: Die Inhalte orientieren sich am aktiven Menüpunkt.<br>
Zeile 3: Jede Auswahl aktualisiert die Überschrift.<br>
Zeile 4: Die Content-Card bleibt optisch eigenständig.<br>
Zeile 5: Der Aufbau folgt dem linken Navigationsbereich.<br>
Zeile 6: Die Breite bleibt flexibel innerhalb des Layouts.<br>
Zeile 7: Lange Inhalte werden im Card-Rahmen geführt.<br>
Zeile 8: Der Text dient als Platzhalter für spätere Inhalte.<br>
Zeile 9: Die Darstellung bleibt auf Desktop und Mobile stabil.<br>
Zeile 10: Die Navigation links steuert den sichtbaren Zustand.<br>
Zeile 11: Der aktive Punkt ist visuell hervorgehoben.<br>
Zeile 12: Inaktive Punkte bleiben als klare Auswahloptionen sichtbar.<br>
Zeile 13: Die Content-Card reagiert auf den ausgewählten Eintrag.<br>
Zeile 14: Die Überschrift übernimmt den Namen des Menüpunkts.<br>
Zeile 15: Der Text kann später durch Fachinhalte ersetzt werden.<br>
Zeile 16: Die Gruppe bleibt als zusammenhängender Bereich lesbar.<br>
Zeile 17: Kartenabstände folgen den vorhandenen Styleguide-Tokens.<br>
Zeile 18: Keine lokalen Sonderregeln sind für den Demo-Text nötig.<br>
Zeile 19: Die Struktur bleibt bewusst einfach und nachvollziehbar.<br>
Zeile 20: Das Layout zeigt Navigation und Inhalt nebeneinander.<br>
Zeile 21: Der linke Bereich bleibt auf die Navigation fokussiert.<br>
Zeile 22: Der rechte Bereich zeigt den zugehörigen Inhalt.<br>
Zeile 23: Der Text dient als Füllmaterial für die Layoutprüfung.<br>
Zeile 24: Die Card-Höhe passt sich dem vorhandenen Inhalt an.<br>
Zeile 25: Scrollverhalten ist in diesem Demo-Zustand nicht nötig.<br>
Zeile 26: Die Darstellung bleibt ohne zusätzliche Interaktion verständlich.<br>
Zeile 27: Weitere Inhalte lassen sich später ergänzen oder ersetzen.<br>
Zeile 28: Die Auswahl folgt weiterhin dem Tab-Button-Verhalten.<br>
Zeile 29: Visuelle Konsistenz hat Vorrang vor dekorativen Effekten.<br>
Zeile 30: Der Demo-Text bleibt neutral und fachlich unaufgeladen.<br>
Zeile 31: Jede Zeile stützt die Prüfung der vertikalen Kartengröße.<br>
Zeile 32: Der Content-Bereich ist damit klar als gefüllte Fläche erkennbar.<br>
Zeile 33: Der Text nutzt die vorhandenen Typografie-Tokens.<br>
Zeile 34: Die Lesbarkeit bleibt auf hellem Inhaltshintergrund hoch.<br>
Zeile 35: Die Spaltenlogik wird durch den Text noch deutlicher.<br>
Zeile 36: Das Beispiel unterstützt die Wahrnehmung des Pattern-Rahmens.<br>
Zeile 37: Der Inhalt bleibt austauschbar und ohne Geschäftslogik.<br>
Zeile 38: Die Group Card dient als Container für den Demo-Inhalt.<br>
Zeile 39: Das Muster zeigt die vorgesehene Struktur des Portals.<br>
Zeile 40: Die finale Zeile schließt den Demo-Block sauber ab.
</p>
</section>
</div>
</section>
<script>
(() => {
const mediaQuery = window.matchMedia('(max-width: 767px)');
const toggle = document.querySelector('[data-left-navigation-toggle]');
const menu = document.getElementById('left-navigation-menu');
const contentHeading = document.querySelector('[data-left-navigation-content-heading]');
if (!toggle || !menu) {
return;
}
const setMenuState = (expanded) => {
menu.hidden = !expanded;
menu.classList.toggle('sg-left-navigation-pattern__menu--collapsed', !expanded);
toggle.setAttribute('aria-expanded', String(expanded));
toggle.textContent = expanded ? 'Ausblenden' : 'Einblenden';
toggle.classList.add('sg-button--active');
toggle.classList.remove('sg-button--inactive');
};
const setContentHeading = (button) => {
if (!contentHeading || !button) {
return;
}
contentHeading.textContent = button.textContent.trim();
};
const syncMode = () => {
if (mediaQuery.matches) {
if (toggle.getAttribute('aria-expanded') !== 'true' && toggle.getAttribute('aria-expanded') !== 'false') {
setMenuState(true);
return;
}
setMenuState(toggle.getAttribute('aria-expanded') !== 'false');
return;
}
menu.hidden = false;
menu.classList.remove('sg-left-navigation-pattern__menu--collapsed');
toggle.setAttribute('aria-expanded', 'true');
toggle.textContent = 'Ausblenden';
toggle.classList.add('sg-button--active');
toggle.classList.remove('sg-button--inactive');
};
toggle.addEventListener('click', () => {
setMenuState(menu.hidden);
});
menu.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
menu.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
otherButton.setAttribute('aria-selected', String(otherButton === button));
});
setContentHeading(button);
});
});
setContentHeading(menu.querySelector('.sg-tab-button[aria-selected="true"]'));
syncMode();
mediaQuery.addEventListener('change', syncMode);
})();
</script>
</body>
</html>
+602
View File
@@ -0,0 +1,602 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern Multiselektions-Pulldown</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern Multiselektions-Pulldown</h1>
<section id="pattern-multiselektions-pulldown">
<p class="sg-preview-label">Pattern: Multiselektions-Pulldown</p>
<div class="sg-options-row" aria-label="Multiselektions-Pulldown Wrapper" data-pattern="multiselektions-pulldown">
<div class="sg-options-row__left" data-pattern-part="multiselektions-pulldown-trigger-area">
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="multiple" data-component="pulldown" data-component-state="active" data-force-active="true">
<span class="sg-activatable-control">
<button class="sg-interaction-element sg-pulldown sg-pulldown--selected sg-form-active sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Multiselektions-Pulldown mit aktiver Auswahl" data-label-base="Multiselektions-Pulldown" data-component-part="pulldown-trigger">
Multiselektions-Pulldown
</button>
</span>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Multiselektions-Pulldown" data-component-part="pulldown-panel">
<div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Multiselektions-Inhalt">
<form class="sg-form-sections-card" action="#" method="post">
<div class="sg-form-sections-card__body" data-pattern-part="form-body">
<section class="sg-form-sections-card__chapter" aria-labelledby="multiselect-block-1">
<h2 id="multiselect-block-1" class="sg-strong sg-form-sections-card__chapter-title">Block 1</h2>
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
<button class="sg-checkbox-field sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Checkbox 1 wählen" data-pulldown-option>
<span class="sg-checkbox-field__mark" aria-hidden="true"></span>
</button>
<span>Checkbox 1</span>
</label>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 1: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-1-label">Slider 1</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="6.5"
aria-labelledby="multiselect-slider-1-label"
disabled
>
<output class="sg-slider-value" for="slider">6.5</output>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 2: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-2-label">Slider 2</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="9.5"
aria-labelledby="multiselect-slider-2-label"
disabled
>
<output class="sg-slider-value" for="slider">9.5</output>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 3: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-3-label">Slider 3</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="5.0"
aria-labelledby="multiselect-slider-3-label"
disabled
>
<output class="sg-slider-value" for="slider">5.0</output>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 4: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-4-label">Slider 4</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="6.5"
aria-labelledby="multiselect-slider-4-label"
disabled
>
<output class="sg-slider-value" for="slider">6.5</output>
</div>
</section>
<section class="sg-form-sections-card__chapter" aria-labelledby="multiselect-block-2">
<h2 id="multiselect-block-2" class="sg-strong sg-form-sections-card__chapter-title">Block 2</h2>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 5: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-5-label">Slider 5</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="3.0"
aria-labelledby="multiselect-slider-5-label"
disabled
>
<output class="sg-slider-value" for="slider">3.0</output>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 6: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-6-label">Slider 6</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="2.5"
aria-labelledby="multiselect-slider-6-label"
disabled
>
<output class="sg-slider-value" for="slider">2.5</output>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Slider 7: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-slider-7-label">Slider 7</span>
<input
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
type="range"
min="1"
max="10"
step="0.1"
value="1.6"
aria-labelledby="multiselect-slider-7-label"
disabled
>
<output class="sg-slider-value" for="slider">1.6</output>
</div>
</section>
<section class="sg-form-sections-card__chapter" aria-labelledby="multiselect-block-3">
<h2 id="multiselect-block-3" class="sg-strong sg-form-sections-card__chapter-title">Block 3</h2>
<div id="component-radio-activatable" class="sg-checkbox-field-option sg-checkbox-field-option--inactive-selectable sg-body sg-radio-activatable-group" data-component="radio-field" data-component-state="inactive-selectable" data-activatable="true" data-activatable-radio-group="true">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Radio Auswahl: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<span class="sg-label" id="multiselect-radio-group-label">Radio Auswahl</span>
<span class="sg-radio-activatable-group__choices">
<span class="sg-radio-activatable-group__choice">
<button class="sg-radio-field sg-radio-field--inactive-selectable" type="button" role="radio" aria-checked="false" aria-label="Radio 1 wählen" aria-describedby="multiselect-radio-group-label">
<span class="sg-radio-field__mark" aria-hidden="true"></span>
</button>
<span>Radio 1</span>
</span>
<span class="sg-radio-activatable-group__choice">
<button class="sg-radio-field sg-radio-field--inactive-selectable" type="button" role="radio" aria-checked="false" aria-label="Radio 2 wählen" aria-describedby="multiselect-radio-group-label">
<span class="sg-radio-field__mark" aria-hidden="true"></span>
</button>
<span>Radio 2</span>
</span>
</span>
</div>
<div class="sg-pulldown-panel__row sg-pulldown-panel__row--disabled" data-pulldown-filter-row data-active="false" data-component-part="pulldown-filter-row">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Pulldown 1: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<p class="sg-pulldown-panel__label sg-body">Pulldown 1</p>
<select class="sg-interaction-element sg-pulldown" aria-label="Pulldown 1 Auswahl" disabled>
<option selected>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</select>
</div>
</section>
<section class="sg-form-sections-card__chapter" aria-labelledby="multiselect-block-4">
<h2 id="multiselect-block-4" class="sg-strong sg-form-sections-card__chapter-title">Block 4</h2>
<div class="sg-pulldown-panel__row sg-pulldown-panel__row--disabled" data-pulldown-filter-row data-active="false" data-component-part="pulldown-filter-row">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Pulldown 2: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<p class="sg-pulldown-panel__label sg-body">Pulldown 2</p>
<select class="sg-interaction-element sg-pulldown" aria-label="Pulldown 2 Auswahl" disabled>
<option selected>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</select>
</div>
<div class="sg-pulldown-panel__row sg-pulldown-panel__row--disabled" data-pulldown-filter-row data-active="false" data-component-part="pulldown-filter-row">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Pulldown 3: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<p class="sg-pulldown-panel__label sg-body">Pulldown 3</p>
<select class="sg-interaction-element sg-pulldown" aria-label="Pulldown 3 Auswahl" disabled>
<option selected>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</select>
</div>
<div class="sg-pulldown-panel__row sg-pulldown-panel__row--disabled" data-pulldown-filter-row data-active="false" data-component-part="pulldown-filter-row">
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung Pulldown 4: aus">
<span class="sg-mode-toggle__switch" aria-hidden="true">
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
<span class="sg-mode-toggle__handle"></span>
</span>
</button>
<p class="sg-pulldown-panel__label sg-body">Pulldown 4</p>
<select class="sg-interaction-element sg-pulldown" aria-label="Pulldown 4 Auswahl" disabled>
<option selected>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</select>
</div>
</section>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
(() => {
const setLocalActivationState = (toggle, isActive) => {
const sliderRow = toggle.closest('.sg-slider-row[data-activatable="true"]');
if (sliderRow) {
const slider = sliderRow.querySelector('.sg-slider');
if (!slider) {
return;
}
sliderRow.dataset.componentState = isActive ? 'active' : 'inactive-selectable';
sliderRow.classList.toggle('sg-slider-row--inactive-selectable', !isActive);
slider.classList.toggle('sg-form-active', isActive);
slider.classList.toggle('sg-form-inactive-selectable', !isActive);
slider.disabled = !isActive;
return;
}
const radioGroup = toggle.closest('[data-activatable-radio-group="true"]');
if (radioGroup) {
const radios = radioGroup.querySelectorAll('.sg-radio-field');
radioGroup.dataset.componentState = isActive ? 'active' : 'inactive-selectable';
radios.forEach((radio) => {
radio.disabled = !isActive;
if (!isActive) {
radio.setAttribute('aria-checked', 'false');
}
const checked = radio.getAttribute('aria-checked') === 'true';
radio.classList.toggle('sg-form-active', checked);
radio.classList.toggle('sg-radio-field--inactive-selectable', !isActive);
});
return;
}
const pulldownRow = toggle.closest('[data-pulldown-filter-row]');
if (pulldownRow) {
const select = pulldownRow.querySelector('.sg-pulldown');
if (!select) {
return;
}
pulldownRow.dataset.active = isActive ? 'true' : 'false';
select.disabled = !isActive;
pulldownRow.classList.toggle('sg-pulldown-panel__row--disabled', !isActive);
select.classList.toggle('sg-pulldown--selected', isActive);
select.classList.toggle('sg-pulldown--inactive-selectable', !isActive);
}
};
document.querySelectorAll('.sg-activation-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = toggle.dataset.active === 'absolute' ? 'relative' : 'absolute';
const isActive = nextState === 'relative';
toggle.dataset.active = nextState;
toggle.setAttribute('aria-label', toggle.getAttribute('aria-label').replace(/(an|aus)$/, isActive ? 'an' : 'aus'));
setLocalActivationState(toggle, isActive);
});
});
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
const forceActive = demo.dataset.forceActive === 'true';
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = forceActive
? labelBase
: (selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase);
trigger.classList.toggle('sg-pulldown--selected', forceActive || selectedCount > 0);
trigger.classList.toggle('sg-form-active', forceActive || selectedCount > 0);
trigger.classList.toggle('sg-pulldown--inactive-selectable', !forceActive && selectedCount === 0);
trigger.setAttribute(
'aria-label',
forceActive || selectedCount > 0 ? `${labelBase} mit aktiver Auswahl` : `${labelBase} ohne aktive Auswahl`
);
};
const updateMultiselectLabelAlignment = () => {
document.querySelectorAll('.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-pulldown-panel').forEach((panel) => {
const labels = panel.querySelectorAll(
'.sg-slider-row[data-activatable="true"] > .sg-label, .sg-radio-activatable-group > .sg-label, [data-pulldown-filter-row] > .sg-pulldown-panel__label'
);
let maxWidth = 0;
labels.forEach((label) => {
const width = Math.ceil(label.scrollWidth || label.getBoundingClientRect().width);
if (width > maxWidth) {
maxWidth = width;
}
});
if (maxWidth > 0) {
panel.style.setProperty('--sg-multiselect-label-column-width', `${maxWidth}px`);
} else {
panel.style.removeProperty('--sg-multiselect-label-column-width');
}
});
};
document.querySelectorAll('.sg-slider-row').forEach((row) => {
const slider = row.querySelector('.sg-slider');
const valueOutput = row.querySelector('.sg-slider-value');
if (!slider || !valueOutput) {
return;
}
const updateSliderState = () => {
const min = Number(slider.min || 0);
const max = Number(slider.max || 100);
const value = Number(slider.value || 0);
const denominator = max - min;
const progress = denominator > 0 ? ((value - min) / denominator) * 100 : 0;
slider.style.setProperty('--sg-slider-progress', `${progress}%`);
valueOutput.textContent = value.toFixed(1);
};
slider.addEventListener('input', () => {
if (row.dataset.activatable === 'true' && row.dataset.componentState !== 'active') {
return;
}
updateSliderState();
});
updateSliderState();
});
document.querySelectorAll('.sg-checkbox-field').forEach((checkbox) => {
checkbox.addEventListener('click', (event) => {
event.stopPropagation();
if (checkbox.disabled) {
return;
}
const activatableOption = checkbox.closest('[data-component="checkbox-field"][data-activatable="true"]');
if (activatableOption) {
checkbox.setAttribute('aria-checked', 'true');
checkbox.classList.add('sg-form-active');
checkbox.classList.remove('sg-checkbox-field--inactive-selectable');
activatableOption.dataset.componentState = 'active';
}
const pulldownDemo = checkbox.closest('.sg-pulldown-demo');
if (pulldownDemo) {
updatePulldownSelectionState(pulldownDemo);
pulldownDemo.dataset.open = 'true';
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
}
});
});
document.querySelectorAll('.sg-radio-field').forEach((radio) => {
radio.addEventListener('click', (event) => {
event.stopPropagation();
if (radio.disabled) {
return;
}
const activatableGroup = radio.closest('[data-activatable-radio-group="true"]');
if (!activatableGroup) {
return;
}
if (activatableGroup.dataset.componentState !== 'active') {
return;
}
const radios = activatableGroup.querySelectorAll('.sg-radio-field');
radios.forEach((otherRadio) => {
otherRadio.setAttribute('aria-checked', String(otherRadio === radio));
otherRadio.disabled = false;
otherRadio.classList.remove('sg-radio-field--inactive-selectable');
otherRadio.classList.toggle('sg-form-active', otherRadio === radio);
});
});
});
document.querySelectorAll('[data-activatable-radio-group="true"]').forEach((group) => {
const isActive = group.dataset.componentState === 'active';
group.querySelectorAll('.sg-radio-field').forEach((radio) => {
radio.disabled = !isActive;
});
});
updateMultiselectLabelAlignment();
window.addEventListener('resize', updateMultiselectLabelAlignment);
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
if (demo.dataset.activatable === 'true') {
trigger.classList.add('sg-pulldown--selected', 'sg-form-active');
trigger.classList.remove('sg-pulldown--inactive-selectable');
}
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
updateMultiselectLabelAlignment();
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
demo.dataset.align = 'left';
panel.style.left = '0px';
panel.style.right = 'auto';
const initialRect = panel.getBoundingClientRect();
let offsetX = 0;
const maxRight = window.innerWidth;
if (initialRect.right > maxRight) {
offsetX -= initialRect.right - maxRight;
}
if (initialRect.left + offsetX < 0) {
offsetX += 0 - (initialRect.left + offsetX);
}
panel.style.left = `${offsetX}px`;
});
});
document.querySelectorAll('[data-pulldown-filter-row]').forEach((row) => {
const select = row.querySelector('.sg-pulldown');
if (!select) {
return;
}
const updateFilterRowState = () => {
const isActive = row.dataset.active === 'true';
row.classList.toggle('sg-pulldown-panel__row--disabled', !isActive);
select.classList.toggle('sg-pulldown--selected', isActive);
select.classList.toggle('sg-pulldown--inactive-selectable', !isActive);
select.disabled = !isActive;
};
updateFilterRowState();
});
document.addEventListener('click', (event) => {
if (event.target.closest('.sg-pulldown-demo')) {
return;
}
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
})();
</script>
</body>
</html>
-236
View File
@@ -1,236 +0,0 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern Multiselektionspulldown</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern Multiselektionspulldown</h1>
<section id="pattern-multiselektionspulldown">
<p class="sg-preview-label">Pattern: Multiselektionspulldown</p>
<div class="sg-multiselect-pulldown-demo" data-pattern="multiselektionspulldown" aria-label="Multiselektionspulldown Kennzahlen">
<div class="sg-multiselect-pulldown-demo__controls" aria-hidden="true">
<button class="sg-interaction-element sg-pulldown sg-pulldown--selected" type="button">Kennzahlen (1)</button>
<span class="sg-input-single-line-wrap sg-multiselect-pulldown-demo__search-wrap" data-has-value="false">
<input class="sg-interaction-element sg-input-single-line" type="text" placeholder="suchen" aria-label="suchen" disabled>
</span>
<span class="sg-table-label sg-multiselect-pulldown-demo__results">236 Treffer</span>
</div>
<div class="sg-pulldown-demo sg-multiselect-pulldown" data-open="true" data-align="left" data-selection-mode="multiple" data-component="pulldown" data-component-context="multiselektionspulldown" data-component-state="selected">
<button
class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger sg-pulldown--selected"
type="button"
aria-expanded="true"
aria-label="Pulldown Kennzahlen mit aktiver Auswahl"
data-component-part="pulldown-trigger"
data-label-base="Kennzahlen"
>
Kennzahlen (1)
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Kennzahlen" data-component-part="pulldown-panel">
<div class="sg-form-sections-card-wrapper sg-multiselect-pulldown__form-wrapper" data-pattern-part="multiselect-form-wrapper">
<form class="sg-form-sections-card sg-multiselect-pulldown__form" action="#" method="post">
<div class="sg-form-sections-card__body sg-multiselect-pulldown__form-body" data-pattern-part="multiselect-form-body">
<div class="sg-multiselect-pulldown__section" aria-labelledby="kennzahlen-score-minimum">
<h2 id="kennzahlen-score-minimum" class="sg-sub-heading sg-multiselect-pulldown__section-title">Scores Minimum</h2>
<label class="sg-checkbox-field-option sg-body sg-multiselect-pulldown__row-label" data-component="checkbox-field" data-component-state="inactive-selectable">
<button class="sg-checkbox-field sg-form-active" type="button" role="checkbox" aria-checked="true" aria-label="Nur Score attraktiv">
<span class="sg-checkbox-field__mark" aria-hidden="true"></span>
</button>
<span>Nur Score "attraktiv"</span>
</label>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-activatable="true" data-active="false" data-decimals="1" aria-disabled="true">
<span class="sg-label">Aktienbewertung</span>
<input class="sg-slider" type="range" min="0" max="10" step="0.1" value="6.5" disabled>
<span class="sg-slider-value">6.5</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="Aktienbewertung aktivieren" data-action="toggle">+</button>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-activatable="true" data-active="false" data-decimals="1" aria-disabled="true">
<span class="sg-label">Wachstum</span>
<input class="sg-slider" type="range" min="0" max="10" step="0.1" value="9.5" disabled>
<span class="sg-slider-value">9.5</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="Wachstum aktivieren" data-action="toggle">+</button>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-activatable="true" data-active="false" data-decimals="1" aria-disabled="true">
<span class="sg-label">Profitabilität</span>
<input class="sg-slider" type="range" min="0" max="10" step="0.1" value="5.0" disabled>
<span class="sg-slider-value">5.0</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="Profitabilität aktivieren" data-action="toggle">+</button>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-activatable="true" data-active="false" data-decimals="1" aria-disabled="true">
<span class="sg-label">Stabilität</span>
<input class="sg-slider" type="range" min="0" max="10" step="0.1" value="6.5" disabled>
<span class="sg-slider-value">6.5</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="Stabilität aktivieren" data-action="toggle">+</button>
</div>
</div>
<div class="sg-multiselect-pulldown__section" aria-labelledby="kennzahlen-marktbewertung-max">
<h2 id="kennzahlen-marktbewertung-max" class="sg-sub-heading sg-multiselect-pulldown__section-title">Marktbewertung Maximum</h2>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-activatable="true" data-active="false" data-decimals="0" aria-disabled="true">
<span class="sg-label">PE</span>
<input class="sg-slider" type="range" min="0" max="60" step="1" value="30" disabled>
<span class="sg-slider-value">30</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="PE aktivieren" data-action="toggle">+</button>
</div>
<div class="sg-slider-row sg-slider-row--inactive-selectable" data-activatable="true" data-active="false" data-decimals="0" aria-disabled="true">
<span class="sg-label">PE forw.</span>
<input class="sg-slider" type="range" min="0" max="50" step="1" value="25" disabled>
<span class="sg-slider-value">25</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="PE forw. aktivieren" data-action="toggle">+</button>
</div>
<div class="sg-slider-row" data-activatable="true" data-active="true" data-decimals="1">
<span class="sg-label">PEG</span>
<input class="sg-slider" type="range" min="0" max="4" step="0.1" value="1.6">
<span class="sg-slider-value">1.6</span>
<button class="sg-activatable-remove sg-multiselect-pulldown__toggle" type="button" aria-label="PEG deaktivieren" data-action="toggle">&times;</button>
</div>
</div>
<div class="sg-multiselect-pulldown__section" aria-labelledby="kennzahlen-weitere-filter">
<h2 id="kennzahlen-weitere-filter" class="sg-sub-heading sg-multiselect-pulldown__section-title">Weitere Filter</h2>
<div class="sg-multiselect-pulldown__radio-row" role="radiogroup" aria-label="Zyklus-Empfehlung">
<span class="sg-label">Zyklus-Empfehlung</span>
<label class="sg-radio-activatable-group__choice sg-body" data-component="radio-field" data-component-state="inactive-selectable">
<button class="sg-radio-field sg-radio-field--inactive-selectable" type="button" role="radio" aria-checked="false" aria-label="kaufen">
<span class="sg-radio-field__mark" aria-hidden="true"></span>
</button>
<span>kaufen</span>
</label>
<label class="sg-radio-activatable-group__choice sg-body" data-component="radio-field" data-component-state="active">
<button class="sg-radio-field" type="button" role="radio" aria-checked="true" aria-label="nicht kaufen">
<span class="sg-radio-field__mark" aria-hidden="true"></span>
</button>
<span>nicht kaufen</span>
</label>
</div>
<div class="sg-multiselect-pulldown__row-label">
<span class="sg-label">Moat mindestens</span>
<button class="sg-interaction-element sg-pulldown sg-multiselect-pulldown__compact-pulldown" type="button" aria-label="Moat mindestens Maessig" data-moat-options="Schwach|Maessig|Stark|Sehr stark" data-moat-index="1">Maessig</button>
</div>
</div>
</div>
<footer class="sg-form-sections-card__actions-segment sg-multiselect-pulldown__actions-segment" data-pattern-part="multiselect-actions-segment">
<div class="sg-form-sections-card__actions"></div>
</footer>
</form>
</div>
</div>
</div>
</div>
</section>
<script>
(() => {
const pattern = document.querySelector('[data-pattern="multiselektionspulldown"]');
if (!pattern) {
return;
}
const formatSliderValue = (row, value) => {
const decimals = Number(row.dataset.decimals || 0);
return Number(value).toFixed(decimals);
};
const updateSliderRowState = (row, isActive) => {
const slider = row.querySelector('.sg-slider');
const toggle = row.querySelector('[data-action="toggle"]');
const label = row.querySelector('.sg-label');
if (!slider || !toggle || !label) {
return;
}
row.dataset.active = String(isActive);
row.classList.toggle('sg-slider-row--inactive-selectable', !isActive);
row.setAttribute('aria-disabled', String(!isActive));
slider.disabled = !isActive;
toggle.textContent = isActive ? '×' : '+';
toggle.setAttribute(
'aria-label',
`${label.textContent?.trim() || 'Filter'} ${isActive ? 'deaktivieren' : 'aktivieren'}`
);
};
pattern.querySelectorAll('.sg-slider-row[data-activatable="true"]').forEach((row) => {
const slider = row.querySelector('.sg-slider');
const valueEl = row.querySelector('.sg-slider-value');
const toggle = row.querySelector('[data-action="toggle"]');
if (!slider || !valueEl || !toggle) {
return;
}
valueEl.textContent = formatSliderValue(row, slider.value);
updateSliderRowState(row, row.dataset.active === 'true');
slider.addEventListener('input', () => {
valueEl.textContent = formatSliderValue(row, slider.value);
});
toggle.addEventListener('click', () => {
updateSliderRowState(row, row.dataset.active !== 'true');
});
});
pattern.querySelectorAll('[data-component="checkbox-field"] .sg-checkbox-field').forEach((checkbox) => {
checkbox.addEventListener('click', () => {
const isChecked = checkbox.getAttribute('aria-checked') === 'true';
const nextState = !isChecked;
checkbox.setAttribute('aria-checked', String(nextState));
checkbox.classList.toggle('sg-form-active', nextState);
checkbox.classList.toggle('sg-checkbox-field--inactive-selectable', !nextState);
});
});
pattern.querySelectorAll('.sg-multiselect-pulldown__radio-row').forEach((group) => {
const options = Array.from(group.querySelectorAll('[role="radio"]'));
options.forEach((radio) => {
radio.addEventListener('click', () => {
options.forEach((other) => {
const selected = other === radio;
other.setAttribute('aria-checked', String(selected));
other.classList.toggle('sg-radio-field--inactive-selectable', !selected);
});
});
});
});
const moatButton = pattern.querySelector('.sg-multiselect-pulldown__compact-pulldown');
if (moatButton) {
const options = (moatButton.dataset.moatOptions || '')
.split('|')
.map((option) => option.trim())
.filter(Boolean);
moatButton.addEventListener('click', () => {
if (options.length === 0) {
return;
}
const currentIndex = Number(moatButton.dataset.moatIndex || 0);
const nextIndex = (currentIndex + 1) % options.length;
moatButton.dataset.moatIndex = String(nextIndex);
moatButton.textContent = options[nextIndex];
moatButton.setAttribute('aria-label', `Moat mindestens ${options[nextIndex]}`);
});
}
})();
</script>
</body>
</html>
+264
View File
@@ -0,0 +1,264 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern Notifications</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern Notifications</h1>
<section id="pattern-notifications">
<p class="sg-preview-label">Pattern: Notifications</p>
<div class="sg-preview-area sg-notifications-pattern">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
</div>
</section>
<section id="pattern-notifications-with-title">
<p class="sg-preview-label">Pattern: Notification with title</p>
<div class="sg-preview-area sg-notifications-pattern">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Veeva Systems Inc Class A</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Veeva Systems Inc Class A</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Veeva Systems Inc Class A</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Veeva Systems Inc Class A</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
</div>
</section>
<section id="pattern-notifications-small">
<p class="sg-preview-label">Pattern: Notifications small</p>
<div class="sg-preview-area sg-notifications-pattern">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-small" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment sg-notifications-pattern__text-segment--small" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-small" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__text-segment--small" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-small" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment sg-notifications-pattern__text-segment--small" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-small" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__text-segment--small" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
zum Unternehmen
</button>
</div>
</article>
</div>
</section>
<script>
const updateNotificationsPatternRowState = () => {
document.querySelectorAll('.sg-notifications-pattern').forEach((grid) => {
const cards = Array.from(grid.querySelectorAll('.sg-notifications-pattern__card'));
grid.classList.remove('sg-notifications-pattern--multi-row');
grid.style.removeProperty('--layout-object-card-shared-width');
if (cards.length <= 1) {
return;
}
const firstTop = cards[0].offsetTop;
const hasMultipleRows = cards.some((card) => card.offsetTop !== firstTop);
if (!hasMultipleRows) {
return;
}
const firstRowCards = cards.filter((card) => card.offsetTop === firstTop);
const referenceCard = firstRowCards[0];
if (!referenceCard) {
return;
}
const referenceWidth = referenceCard.getBoundingClientRect().width;
grid.style.setProperty('--layout-object-card-shared-width', `${referenceWidth}px`);
grid.classList.add('sg-notifications-pattern--multi-row');
});
};
window.addEventListener('load', updateNotificationsPatternRowState);
window.addEventListener('resize', updateNotificationsPatternRowState);
</script>
</body>
</html>
+64 -8
View File
@@ -26,9 +26,9 @@
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
@@ -44,7 +44,7 @@
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a></div></div></header>
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
@@ -56,7 +56,7 @@
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a></div></div></header>
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
@@ -68,7 +68,7 @@
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a></div></div></header>
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
@@ -80,7 +80,7 @@
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a></div></div></header>
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
@@ -92,7 +92,7 @@
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link sg-body" href="#">Menüpunkt</a></div></div></header>
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
@@ -103,6 +103,62 @@
</footer>
</article>
</div>
<h2 class="sg-sub-heading sg-section-h2">Object Card Content Basic</h2>
<p class="sg-preview-label">Pattern: Object Card Content Basic</p>
<p class="sg-body">Hinweis: Diese Variante ist für spezifische Inhalte gedacht, die eine Nutzerinteraktion erfordern, zum Beispiel Zustimmungen oder Freigaben. Im Styleguide wird hier nur das Card-Layout gezeigt.</p>
<article class="sg-card sg-object-card sg-object-card--content-basic sg-object-card-content-basic" data-pattern="object-card-content-basic" aria-label="Objekt Card Content Basic">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-content-basic-header">
<div class="sg-strong">Zustimmung zu Geschäftsbedingungen</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content-basic-content">
<p class="sg-body">Bevor Sie fortfahren, prüfen Sie bitte die Inhalte der Geschäftsbedingungen und bestätigen Sie die Zustimmung im Zielsystem.</p>
<p class="sg-body">Die Karte ist bewusst kompakt gehalten und für lesbare, interaktionspflichtige Inhalte auf Desktop mittig ausgerichtet.</p>
</div>
</article>
<h2 class="sg-sub-heading sg-section-h2">Object Card variable height</h2>
<p class="sg-preview-label">Pattern: Object Card variable height</p>
<p class="sg-body">Hinweis: In dieser Variante ist die komplette Karte in der Höhe flexibel. Die Segmenthöhen ergeben sich direkt aus dem Inhalt, dadurch sind die Karten im Grid bewusst unterschiedlich hoch.</p>
<div class="sg-object-card-grid">
<article class="sg-card sg-object-card sg-object-card--variable-height" data-pattern="object-card" aria-label="Objekt Card variable Höhe">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
<div class="sg-strong">Alcon Inc.</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Kurzer Inhalt für eine kompakte Karte mit wenig vertikalem Platzbedarf.</p>
</div>
</article>
<article class="sg-card sg-object-card sg-object-card--variable-height" data-pattern="object-card" aria-label="Objekt Card variable Höhe">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
<div class="sg-strong">Meyer Optik AG</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Etwas längerer Text mit mehr Inhalt. Die Karte wächst hier sichtbar mit dem Segment, weil der Body bewusst mehr Umbruchzeilen erzeugt und damit die Höhe definiert.</p>
</div>
</article>
<article class="sg-card sg-object-card sg-object-card--variable-height" data-pattern="object-card" aria-label="Objekt Card variable Höhe">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
<div class="sg-strong">Nordwind Therapeutics Holding</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Der Inhalt ist hier knapp, aber die Karte bleibt flexibel und nimmt nur so viel Höhe ein wie die Segmente tatsächlich benötigen.</p>
</div>
</article>
<article class="sg-card sg-object-card sg-object-card--variable-height" data-pattern="object-card" aria-label="Objekt Card variable Höhe">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
<div class="sg-strong">Valencia Holding Group International</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Dies ist die längste Variante in der Demo. Sie zeigt, dass der Body die Kartenhöhe direkt mitprägt, ohne dass ein fixer Kartenrahmen die Inhalte begrenzt oder künstlich streckt.</p>
</div>
</article>
</div>
</section>
<script>
+24 -2
View File
@@ -90,7 +90,24 @@
</div>
</section>
<section id="pattern-list-group-card-height-600">
<p class="sg-preview-label">Pattern: List Group Card</p>
<p class="sg-body sg-object-group-card__hint">Variante: List Group Card, identisch, nur die Höhe ist 600px.</p>
<div class="sg-object-card-grid sg-list-group-card--height-600" aria-label="List Group Card Höhe 600px"></div>
</section>
<script>
const populateListGroupCardVariant = () => {
const sourceGrid = document.querySelector('#pattern-object-group-card .sg-object-card-grid');
const variantGrid = document.querySelector('#pattern-list-group-card-height-600 .sg-object-card-grid');
if (!sourceGrid || !variantGrid || variantGrid.children.length > 0) {
return;
}
variantGrid.innerHTML = sourceGrid.innerHTML;
};
const updateObjectCardGridRowState = () => {
document.querySelectorAll('.sg-object-card-grid').forEach((grid) => {
const cards = Array.from(grid.querySelectorAll('.sg-object-card'));
@@ -117,12 +134,17 @@
}
const referenceWidth = referenceCard.getBoundingClientRect().width;
grid.style.setProperty('--layout-object-card-shared-width', `${referenceWidth}px`);
const maxWidth = parseFloat(getComputedStyle(referenceCard).maxWidth);
const sharedWidth = Number.isFinite(maxWidth) ? Math.min(referenceWidth, maxWidth) : referenceWidth;
grid.style.setProperty('--layout-object-card-shared-width', `${sharedWidth}px`);
grid.classList.add('sg-object-card-grid--multi-row');
});
};
window.addEventListener('load', updateObjectCardGridRowState);
window.addEventListener('load', () => {
populateListGroupCardVariant();
updateObjectCardGridRowState();
});
window.addEventListener('resize', updateObjectCardGridRowState);
</script>
+69 -64
View File
@@ -120,6 +120,69 @@
</div>
</section>
<section id="pattern-options-row-left-only">
<p class="sg-preview-label">Pattern: Options row left only</p>
<p class="sg-table-label" style="color: var(--text-options-row-description);">
Desktop/Tablet: nur linksbündige Elemente innerhalb einer gemeinsamen Options Row.
</p>
<p class="sg-table-label" style="color: var(--text-options-row-description);">
Mobile: keine zweite Segmentierung, die linke Gruppe bleibt als einziger Block erhalten.
</p>
<div class="sg-options-row sg-options-row--left-only" aria-label="Optionszeile nur links" data-pattern="options-row-left-only">
<div class="sg-options-row__left" data-pattern-part="options-row-primary-actions">
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Kategorie" data-component-part="pulldown-trigger" data-label-base="Kategorie">
Kategorie
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Kategorie" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Kategorienoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 1</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 2</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 3</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 4</span>
</li>
<li class="sg-pulldown-option sg-pulldown-option--disabled">
<span>Menüpunkt 5</span>
</li>
</ul>
</div>
</div>
<div class="sg-search-field-row">
<span class="sg-input-single-line-wrap sg-search-field-input" data-has-value="false" data-component="single-line-input" data-component-context="options-row" data-component-state="inactive-selectable">
<input
class="sg-interaction-element sg-input-single-line"
type="text"
placeholder="Suche"
aria-label="Suche"
>
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-component-part="input-clear-button">×</button>
</span>
<span class="sg-search-result-count sg-table-label" aria-live="polite" data-pattern-part="options-row-search-result-count">0 Treffer</span>
</div>
</div>
</div>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
@@ -193,14 +256,6 @@
}
});
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
@@ -209,13 +264,14 @@
return;
}
const triggerRect = trigger.getBoundingClientRect();
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
if (panelRect.width > triggerRect.width || panelRect.right > window.innerWidth) {
demo.dataset.align = 'right';
}
@@ -282,67 +338,16 @@
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
if (!button || !panel) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-help-icon-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-help-icon');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.align = 'left';
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
wrap.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo'],
});
document.addEventListener('click', (event) => {
if (event.target.closest('.sg-help-icon-wrap') || event.target.closest('.sg-pulldown-demo')) {
if (event.target.closest('.sg-pulldown-demo')) {
return;
}
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
+312
View File
@@ -0,0 +1,312 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Page Layout App</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout Page Layout App</h1>
<main aria-label="Page Layout App">
<header class="sg-portal-header" aria-label="Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">ValueStockFinder</p>
<div class="sg-portal-header__menu-wrap sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="default" data-component-context="portal-header" data-pattern-part="portal-header-action">
<button class="sg-interaction-element sg-sandwich-button" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Updates</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Titel</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Gruppen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Listen</button>
</nav>
</div>
</header>
<div class="sg-options-row" aria-label="Optionszeile" data-pattern="options-row">
<div class="sg-options-row__left" data-pattern-part="options-row-primary-actions">
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Sortierung" data-component-part="pulldown-trigger" data-label-base="Sortierung">
Sortierung
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Sortierung" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Sortierungsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 1</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 2</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 3</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 4</span>
</li>
<li class="sg-pulldown-option sg-pulldown-option--disabled">
<span>Menüpunkt 5</span>
</li>
</ul>
</div>
</div>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Region" data-component-part="pulldown-trigger" data-label-base="Region">
Region
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Region" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Regionsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 1</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 2</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 3</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 4</span>
</li>
<li class="sg-pulldown-option sg-pulldown-option--disabled">
<span>Menüpunkt 5</span>
</li>
</ul>
</div>
</div>
<div class="sg-search-field-row">
<span class="sg-input-single-line-wrap sg-search-field-input" data-has-value="false" data-component="single-line-input" data-component-context="options-row" data-component-state="inactive-selectable">
<input
class="sg-interaction-element sg-input-single-line"
type="text"
placeholder="Suche"
aria-label="Suche"
>
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-component-part="input-clear-button">×</button>
</span>
<span class="sg-search-result-count sg-table-label" aria-live="polite" data-pattern-part="options-row-search-result-count">0 Treffer</span>
</div>
</div>
<div class="sg-options-row__right" data-pattern-part="options-row-secondary-actions">
<button class="sg-mode-toggle" type="button" data-active="relative" aria-label="Modus Schieber global: relativ aktiv" data-component="mode-toggle" data-component-context="options-row">
<span class="sg-mode-toggle__label" data-component-part="toggle-label">absolut</span>
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
</span>
<span class="sg-mode-toggle__label" data-component-part="toggle-label">relativ</span>
</button>
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="options-row">
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button>
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.
</span>
</span>
</div>
</div>
<div class="sg-transparent-card sg-page-layout-app__heading-block" aria-label="H1 Bereich" data-component="transparent-card">
<h1 class="sg-heading-h1 sg-text-on-dark">H1 Überschrift</h1>
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--sixty-width">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer convallis purus sed urna ultricies, id aliquet justo malesuada. Morbi luctus, augue in cursus ultrices, justo lorem posuere mi, at suscipit est turpis vitae ipsum.
</p>
</div>
<div class="sg-group-card sg-group-card--margin-after-large" data-component="group-card">
<div class="sg-group-card__header-row">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading">Seiteninhalt</h2>
</div>
<article class="sg-card" data-component="card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Inhalt</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">
Zeile 01<br>
Zeile 02<br>
Zeile 03<br>
Zeile 04<br>
Zeile 05<br>
Zeile 06<br>
Zeile 07<br>
Zeile 08<br>
Zeile 09<br>
Zeile 10<br>
Zeile 11<br>
Zeile 12<br>
Zeile 13<br>
Zeile 14<br>
Zeile 15<br>
Zeile 16<br>
Zeile 17<br>
Zeile 18<br>
Zeile 19<br>
Zeile 20<br>
Zeile 21<br>
Zeile 22<br>
Zeile 23<br>
Zeile 24<br>
Zeile 25<br>
Zeile 26<br>
Zeile 27<br>
Zeile 28<br>
Zeile 29<br>
Zeile 30
</p>
</div>
</article>
</div>
</main>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs, .sg-portal-header__menu-wrap .sg-tab-button-group').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
if (!button) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
selectableOptions.forEach((option) => {
const optionRow = option.closest('.sg-pulldown-option');
if (!optionRow) {
return;
}
optionRow.classList.toggle(
'sg-pulldown-option--selected',
option.getAttribute('aria-checked') === 'true'
);
});
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
trigger.setAttribute(
'aria-label',
selectedCount > 0 ? `Pulldown ${labelBase} mit aktiver Auswahl` : `Pulldown ${labelBase} ohne aktive Auswahl`
);
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
updatePulldownSelectionState(demo);
});
demo.querySelectorAll('[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const nextChecked = option.getAttribute('aria-checked') !== 'true';
option.setAttribute('aria-checked', String(nextChecked));
updatePulldownSelectionState(demo);
});
});
updatePulldownSelectionState(demo);
});
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
</script>
</body>
</html>
+97
View File
@@ -0,0 +1,97 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Page Layout Public</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout Page Layout Public</h1>
<main aria-label="Page Layout Public">
<header class="sg-portal-header sg-portal-header--auth-segment" aria-label="Public Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__auth-row" data-pattern-part="portal-header-action">
<div class="sg-tab-button-group" role="tablist" aria-label="Anmeldung" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">
Login
</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">
Registrieren
</button>
</div>
</div>
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">Portalname</p>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Inhalt 1</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Inhalt 2</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Inhalt 3</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Inhalt 4</button>
</nav>
</div>
</header>
<div class="sg-page-layout-public__content-mirror">
<div class="sg-page-layout-public__heading-block" aria-label="H1 Bereich">
<h1 class="sg-heading-h1 sg-text-on-dark">H1 Überschrift</h1>
<p class="sg-body sg-text-on-dark sg-text-layout-pattern__sample">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer convallis purus sed urna ultricies, id aliquet justo malesuada. Morbi luctus, augue in cursus ultrices, justo lorem posuere mi, at suscipit est turpis vitae ipsum.
</p>
</div>
<article class="sg-card sg-card--content-card sg-card--content-card-dark sg-page-layout-public__footer-card" data-component="content-card" aria-label="Fusszeile">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__two-column" data-pattern-part="text-block-two-column">
<p class="sg-body sg-text-layout-pattern__column">
Footer links: Platzhaltertext fuer allgemeine Hinweise, Navigation oder Kontaktinformationen im zweispaltigen Layout.
</p>
<p class="sg-body sg-text-layout-pattern__column">
Footer rechts: Platzhaltertext fuer ergaenzende Angaben, rechtliche Hinweise oder sekundäre Footer-Inhalte im gleichen Raster.
</p>
</div>
</div>
</article>
</div>
</main>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs, .sg-portal-header__auth-row .sg-tab-button-group, .sg-portal-header__menu-wrap .sg-tab-button-group').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
</script>
</body>
</html>
+59 -68
View File
@@ -40,8 +40,8 @@
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link sg-body" href="#" data-component-part="sandwich-menu-link">Logout</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
@@ -59,6 +59,55 @@
</p>
</article>
<section id="pattern-public-portal-header">
<h1 class="sg-main-heading">Pattern Public Portal Header</h1>
<p class="sg-preview-label">Pattern: Public Portal Header</p>
<p class="sg-table-label sg-text-on-dark">
Desktop/Tablet: Header skaliert über die verfügbare Breite.
</p>
<p class="sg-table-label sg-text-on-dark">
Mobile: Login/Registrieren und Portaltitel in der ersten Zeile; Navigationstasten in einer eigenen Zeile darunter.
</p>
<article class="sg-portal-header-pattern-variant" aria-label="Public Portal Header ohne Options Row">
<p class="sg-table-label sg-portal-header-pattern-variant__label sg-text-on-dark">
Variante: Public Portal Header ohne Options Row
</p>
<header class="sg-portal-header sg-portal-header--auth-segment" aria-label="Public Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__auth-row" data-pattern-part="portal-header-action">
<div class="sg-tab-button-group" role="tablist" aria-label="Anmeldung" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">
Login
</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">
Registrieren
</button>
</div>
</div>
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">Portalname</p>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Inhalt 1</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Inhalt 2</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Inhalt 3</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Inhalt 4</button>
</nav>
</div>
</header>
<p class="sg-table-label sg-portal-header-pattern-variant__next-element sg-text-on-dark">
Nächstes Element (Abstand nach unten: spacing-large)
</p>
</article>
</section>
<article class="sg-portal-header-pattern-variant" aria-label="Portal Header mit Options Row">
<p class="sg-table-label sg-portal-header-pattern-variant__label sg-text-on-dark">
Variante: Portal Header mit Options Row
@@ -78,8 +127,8 @@
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link sg-body" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link sg-body" href="#" data-component-part="sandwich-menu-link">Logout</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
@@ -195,8 +244,9 @@
</article>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs').forEach((group) => {
document.querySelectorAll('.sg-portal-header__tabs, .sg-portal-header__auth-row .sg-tab-button-group, .sg-portal-header__menu-wrap .sg-tab-button-group').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
@@ -294,14 +344,6 @@
}
});
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
@@ -383,52 +425,9 @@
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
if (!button || !panel) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-help-icon-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-help-icon');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.align = 'left';
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
wrap.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
@@ -466,18 +465,10 @@
});
}
if (event.target.closest('.sg-help-icon-wrap') || event.target.closest('.sg-pulldown-demo')) {
if (event.target.closest('.sg-pulldown-demo')) {
return;
}
document.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
+64
View File
@@ -0,0 +1,64 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern Text Layouts</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern Text Layouts</h1>
<section id="pattern-text-layouts">
<p class="sg-preview-label">Pattern: Text Layout ganze Breite</p>
<div class="sg-text-layout-pattern" data-pattern="text-layout-ganze-breite" aria-label="Text Layout ganze Breite">
<div class="sg-text-layout-pattern__preview-surface">
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--full-width" data-pattern-part="text-block-full-width">
Text 100% Breite: Dieser Textblock nimmt die komplette verfügbare Breite des Containers ein und eignet sich für lineare Erklärungen, einleitende Kontexte und Fliesstext ohne Nebenspalte.
</p>
</div>
</div>
<p class="sg-preview-label">Pattern: Text 60% Breite</p>
<div class="sg-text-layout-pattern" data-pattern="text-layout-sechzig-prozent" aria-label="Text Layout 60 Prozent Breite">
<div class="sg-text-layout-pattern__preview-surface">
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--sixty-width" data-pattern-part="text-block-sixty-width">
Text 60% Breite: Dieser Textblock nutzt sechzig Prozent der Containerbreite und schafft dadurch bewusst mehr Luft für begleitende Inhalte wie Metriken, Visuals oder Kontextinformationen.
</p>
</div>
</div>
<p class="sg-preview-label">Pattern: Text zweispaltig (mobil zweispaltig)</p>
<div class="sg-text-layout-pattern" data-pattern="text-layout-zweispaltig" aria-label="Text Layout zweispaltig mobil zweispaltig">
<div class="sg-text-layout-pattern__preview-surface">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__two-column" data-pattern-part="text-block-two-column">
<p class="sg-body sg-text-layout-pattern__column">
Text zweispaltig links: Dieses Layout teilt den Text in zwei gleich breite Spalten mit jeweils fünfzig Prozent Breite auf. Es eignet sich besonders für längere inhaltliche Abschnitte, in denen eine kompaktere Zeilenlänge die Lesbarkeit verbessert.
</p>
<p class="sg-body sg-text-layout-pattern__column">
Text zweispaltig rechts: Gleichzeitig bleibt die Informationsdichte hoch, ohne dass der visuelle Rhythmus in langen einspaltigen Textflächen verloren geht. Durch die symmetrische Aufteilung entstehen klare Leseachsen für Analyse- und Detailseiten.
</p>
</div>
</div>
</div>
<p class="sg-preview-label">Pattern: Dreispaltig verteilt (mobil dreispaltig)</p>
<div class="sg-text-layout-pattern" data-pattern="text-layout-dreispaltig-verteilt" aria-label="Text Layout dreispaltig verteilt mobil dreispaltig">
<div class="sg-text-layout-pattern__preview-surface">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__three-column-distributed" data-pattern-part="text-block-three-column-distributed">
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-left">
Linke Spalte linksbündig: Diese Spalte führt den Inhalt mit einer klaren Startkante und eignet sich für einleitende Aussagen oder Kontext, die direkt in den Lesefluss einsteigen sollen.
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-center">
Mittlere Spalte mittelachsig: Diese Spalte zentriert den Text auf der Mittelachse und eignet sich für vergleichende Kernaussagen, die visuell als Schwerpunkt zwischen den Randspalten stehen sollen.
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-right">
Rechte Spalte rechtsbündig: Diese Spalte schließt den Abschnitt mit einer klaren Endkante ab und eignet sich für ergänzende Hinweise oder abschließende Perspektiven im gleichen Inhaltsblock.
</p>
</div>
</div>
</div>
</section>
</body>
</html>
@@ -0,0 +1,469 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF Card Listen Seite Fundamentalanalyse Drawer</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF Fundamentalanalyse Drawer</h1>
<section class="sg-card-list-page" aria-label="VSF Fundamentalanalyse Drawer Seite">
<div class="sg-navigation-card-layout">
<div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigation Zurück zur Liste oben">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="./vsf-card-listen-seite.html" data-component="hyperlink">zurück zur Liste</a>
</div>
</div>
</article>
</div>
</div>
<article class="sg-card sg-vsf-drawer-card" data-component="card" data-pattern="card" aria-label="Card Western Digital Corporation">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-inline-header-row" data-pattern-part="card-header">
<h2 class="sg-heading-h2 sg-vsf-drawer-object-card__heading">Western Digital Corporation</h2>
<div class="sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Objekt-Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Objekt-Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-vsf-drawer-card__content" data-pattern-part="card-body">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__two-column" data-pattern-part="text-block-two-column">
<p class="sg-body sg-text-layout-pattern__column">
Ticker: WDC<br>
Region: Amerika<br>
Sub-Region: Nordamerika<br>
Land: Vereinigte Staaten von Amerika
</p>
<p class="sg-body sg-text-layout-pattern__column">
ISIN: US9581021055<br>
Industrie: Computer Hardware
</p>
</div>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-vsf-drawer-card__actions-segment" data-pattern-part="card-actions">
<p id="vsf-business-model-text" class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--full-width" data-pattern-part="text-block-full-width" hidden>
Produkte und Lösungen<br>
Western Digital Corporation produziert Festplatten (Hard Disk Drives, HDD) in verschiedenen Formfaktoren und Kapazitäten. Zentrale Produktkategorien umfassen Marken wie WD Blue für allgemeine Computing-Anwendungen, WD Purple und WD Purple Pro für Überwachungssysteme, WD Red, WD Red Plus und WD Red Pro für Netzwerkspeicher (NAS) und kleine Büroumgebungen, WD Black für Gaming und Hochleistung, WD Gold für Unternehmensanwendungen sowie Ultrastar für Rechenzentren. Ergänzt werden diese durch externe Gehäuse wie My Passport und My Book sowie Netzwerkspeichersysteme der My Cloud-Serie. Seit der Abspaltung des Flash-Geschäfts 2025 konzentriert sich das Unternehmen ausschliesslich auf HDD-Technologien.<br><br>
Zielmärkte und Kunden<br>
Die wichtigsten Kundensegmente umfassen Endverbraucher für Desktop-Computer und Gaming, kleine Büros und Home-Office-Nutzer für NAS-Systeme, Überwachungsanbieter für Sicherheitslösungen, Unternehmen für Server- und Enterprise-Speicher sowie Rechenzentren für Hochkapazitäts-Datenspeicherung. Geografisch bedient das Unternehmen globale Märkte mit Schwerpunkt in Nordamerika, Europa, Asien-Pazifik und aufstrebenden Regionen wie Südostasien. Die Produktion erfolgt primär in Thailand und früher in Malaysia.<br><br>
Geschäftsmodell<br>
Western Digital agiert als vertikal integrierter Hersteller von Datenspeichergeräten mit Fokus auf Festplatten-Produktion. Die Wertschöpfungskette umfasst Forschung und Entwicklung zu magnetischen Aufzeichnungstechnologien, Fertigung von Platten, Köpfen und Controllern sowie Montage in San-Jose-basierten Einrichtungen und asiatischen Fabriken. Durch Akquisitionen wie HGST (2012) und frühere Read-Rite hat es Assets in Medien und Komponenten aufgebaut, was eine hohe Eigenfertigung ermöglicht. Das Modell basiert auf skalierbarer Massenproduktion für standardisierte Speicherplattformen.<br><br>
Erlösstruktur<br>
Die Umsatzquellen gliedern sich in Segmente für Client-Computing (WD Blue, WD Black), Überwachung (WD Purple), NAS und SMB (WD Red-Serie), Enterprise (WD Gold) und Rechenzentren (Ultrastar). Der Verkauf erfolgt mechanisch über Direktverkäufe an Original Equipment Manufacturer (OEM), Distributoren und Einzelhändler sowie über eigene Kanäle für externe Produkte. Die Konzentration liegt bei Enterprise- und Datacenter-Segmenten mit höheren Kapazitäten, während Client-Segmente Volumen generieren; keine Abonnements oder transaktionsbasierten Modelle.<br><br>
Marktposition und Wettbewerbsvorteile<br>
Western Digital hält eine führende Marktstellung als grösster traditioneller HDD-Hersteller weltweit nach der HGST-Integration. Strukturelle Vorteile umfassen vertikale Integration in Plattenmedien, Schreib-/Leseköpfe und Controller-Technologie sowie heliumgefüllte Hochkapazitätsmodelle bis 14 TB. Patente in Riesen-Magnetowiderstands-Köpfen (GMR) und Produktionskapazitäten in effizienten Fabriken sichern Skaleneffekte gegenüber Wettbewerbern.
</p>
<button id="vsf-business-model-toggle" class="sg-interaction-element sg-button" type="button" aria-controls="vsf-business-model-text" aria-expanded="false">Geschäftsmodell anzeigen</button>
</footer>
</article>
<div class="sg-transparent-card sg-analysis-intro-block" data-component="transparent-card">
<h2 class="sg-heading-h2 sg-text-on-dark sg-card-list-page__title-row">Fundamentalanalyse vom 12.5.2026 <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></h2>
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--full-width" data-pattern-part="text-block-full-width">
Nächste Analyse: nicht bekannt
</p>
</div>
<div class="sg-content-block-card-group" data-pattern="card-gruppe-mit-tastennavigation">
<div class="sg-tab-button-group sg-content-block-card-group__tabs" role="tablist" aria-label="Fundamentalanalyse Navigation" data-component="tab-navigation" data-component-size="large">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" aria-controls="vsf-fundamental-tab-panel-1" id="vsf-fundamental-tab-1" data-component-part="tab-button">Gesamtbewertung</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-2" id="vsf-fundamental-tab-2" data-component-part="tab-button">Marktbewertung</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-3" id="vsf-fundamental-tab-3" data-component-part="tab-button">Wachstum</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-4" id="vsf-fundamental-tab-4" data-component-part="tab-button">Profitabilität</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-5" id="vsf-fundamental-tab-5" data-component-part="tab-button">Stabilität</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-6" id="vsf-fundamental-tab-6" data-component-part="tab-button">TAM</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-7" id="vsf-fundamental-tab-7" data-component-part="tab-button">Zyklus</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-8" id="vsf-fundamental-tab-8" data-component-part="tab-button">Moat</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-fundamental-tab-panel-9" id="vsf-fundamental-tab-9" data-component-part="tab-button">Technologie</button>
</div>
<div class="sg-content-block-card-group__panels">
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-1" role="tabpanel" aria-labelledby="vsf-fundamental-tab-1">
<div class="sg-content-cards-group" data-pattern="content-cards-group" aria-label="Card Gruppe Gesamtbewertung">
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Gesamtbewertung">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Gesamtbewertung <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<div class="sg-score-bar-list sg-score-bar-list--single-score" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state"><strong class="sg-score-bar-label">(9.9)</strong> attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--white" data-component-part="card-body">
<p class="sg-body">
<strong>Attraktiv. Starke Profitabilitäts- und Gewinnwachstumsdynamik durch KI-Nachfrage, solide Bilanz. Ambitionierte Bewertung setzt perfekte Ausführung voraus.</strong>
</p>
<p class="sg-body">
Western Digital repräsentiert eine hochgradig zyklische, aber aktuell von einem strukturellen KI-Trend getragene Wachstumsgeschichte. Die zentrale Investment-These lautet: Das Unternehmen profitiert kurzfristig von einer außergewöhnlichen Nachfrage nach Hochkapazitäts-Festplatten für Rechenzentren, was zu einer explosiven Ergebnisdynamik führt, jedoch zu einer ambitionierten Bewertung, die eine perfekte Ausführung voraussetzt.
</p>
<p class="sg-body">
Die entscheidenden Stärken sind die starke Profitabilitätsverbesserung mit hohen Kapitalrenditen, die robuste finanzielle Stabilität mit niedriger Verschuldung sowie die Skalenvorteile aus der vertikalen Integration. Dem stehen klare Risiken gegenüber: ein extrem hohes zyklisches Risiko mit Nachfrageschwankungen bis zu 40 Prozent, eine nur mäßig verteidigungsfähige Wettbewerbsposition unter Druck durch chinesische Konkurrenten und disruptive Technologien sowie eine Bewertung, die einen erheblichen Aufschlag auf das historische Niveau darstellt. Der zentrale Zielkonflikt liegt zwischen dem außergewöhnlichen kurzfristigen Wachstum und der langfristigen Nachhaltigkeit des Geschäftsmodells in einer hart umkämpften, kapitalintensiven Branche.
</p>
<p class="sg-body">
Die Qualität des Unternehmens ist aufgrund seiner zyklischen Natur und der angreifbaren Wettbewerbsvorteile als mittel einzustufen. Für einen GARP-Investor ist das Investment aktuell neutral bis nicht attraktiv. Zwar sind Timing-Faktoren durch die zyklische Erholung und den KI-Rückenwind günstig, die extreme Bewertung (KGV nahe 44-47) spiegelt dieses Momentum jedoch bereits vollständig wider und bietet kein Margin of Safety. Das Investment eignet sich nur für risikobewusste Anleger, die auf eine Fortsetzung des KI-Superzyklus spekulieren.
</p>
</div>
</article>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Unterschied zur letzten Analyse vom 1.5.2026">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Unterschied zur letzten Analyse vom 1.5.2026 <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Die Investment-Story hat sich insgesamt verbessert, da sich die strukturellen Wachstumstreiber konkretisiert und die Profitabilität deutlich beschleunigt hat.</p>
<p class="sg-body">Die entscheidenden Veränderungen betreffen das Wachstumstempo und die Margenentwicklung. Das Umsatzwachstum beschleunigte sich auf 25 Prozent im Jahresvergleich, angetrieben von einer 28-prozentigen Zunahme im Cloud-Segment. Die bereinigte Bruttomarge stieg um 770 Basispunkte auf 46,1 Prozent, unterstützt durch eine günstigere Produktmischung und Skaleneffekte. Zudem wurde die Prognose für das kommende Quartal auf ein Wachstum von 40 Prozent angehoben, was auf eine anhaltend starke Nachfrage hindeutet.</p>
<p class="sg-body">Diese Entwicklungen bestätigen die ursprüngliche These eines durch künstliche Intelligenz getriebenen Speicher-Superzyklus und stärken sie sogar. Das verbesserte Profitabilitätsniveau und die höheren Wachstumsprognosen senken das Risiko einer kurzfristigen zyklischen Abschwächung, während die Bewertung weiterhin unter dem historischen Durchschnitt bleibt. Das Chance-Risiko-Profil hat sich somit zugunsten der Chancen verschoben.</p>
</div>
</article>
</div>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-2" role="tabpanel" aria-labelledby="vsf-fundamental-tab-2" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Marktbewertung">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Marktbewertung <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<div class="sg-score-bar-list sg-score-bar-list--single-score" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state"><strong class="sg-score-bar-label">(9.9)</strong></p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<table class="sg-data-table" aria-label="Marktbewertung Kennzahlen" data-component="data-table">
<thead>
<tr>
<th data-component-part="data-table-header-cell">Kennzahl</th>
<th data-component-part="data-table-header-cell">Wert</th>
</tr>
</thead>
<tbody>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">27.5</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">26.4</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PEG Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value sg-score-state--positive" data-component-part="data-table-value-cell">0.35</td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body">
<p class="sg-body">Graphik</p>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Die Aktie von Western Digital wird mit einem Kurs-Gewinn-Verhältnis für das nächste Jahr von knapp 44 bis 47 bewertet. Dies stellt einen erheblichen Aufschlag gegenüber dem historischen Fünfjahresdurchschnitt von etwa 19,5 dar. Diese Bewertungsprämie ist durch ein außergewöhnliches Ergebniswachstum begründet. Für das Geschäftsjahr 2026 erwarten Analysten ein bereinigtes Ergebnis je Aktie, das sich um etwa 81 bis 100 Prozent erhöht. Für das folgende Jahr wird ein weiterer Anstieg auf rund 13,82 Dollar prognostiziert.</p>
<p class="sg-body">Diese Dynamik speist sich aus der künstlichen Intelligenz getriebenen Nachfrage nach hochkapazitiven Festplatten in Rechenzentren. Das Cloud-Segment des Unternehmens wächst mit 28 bis 40 Prozent im Jahresvergleich und generiert mittlerweile 89 Prozent der Umsätze. Zugleich expandiert die Bruttomarge strukturell, was auf Preissetzungsmacht und positive Produktmix-Effekte hindeutet. Das gegenwärtige Bewertungsniveau setzt allerdings eine perfekte Ausführung voraus. Sollte der Superzyklus der künstlichen Intelligenz schwächer ausfallen oder es zu Überkapazitäten bei Halbleitern kommen, droht eine Bewertungskorrektur. Zum jetzigen Zeitpunkt erscheint die Bewertung ambitioniert, aber im Kontext des beschleunigten Ergebniswachstums nicht irrational. Anleger zahlen für das Umsatzmomentum und die strukturelle Margenverbesserung, nicht jedoch für überdurchschnittliche Langzeitgewinne.</p>
</div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-3" role="tabpanel" aria-labelledby="vsf-fundamental-tab-3" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Wachstum">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Wachstum <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<div class="sg-score-bar-list sg-score-bar-list--single-score" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state"><strong class="sg-score-bar-label">(9.9)</strong></p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<table class="sg-data-table" aria-label="Wachstum Kennzahlen" data-component="data-table">
<thead>
<tr>
<th data-component-part="data-table-header-cell">Kennzahl</th>
<th data-component-part="data-table-header-cell">Wert</th>
</tr>
</thead>
<tbody>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">27.5</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">26.4</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PEG Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value sg-score-state--positive" data-component-part="data-table-value-cell">0.35</td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body">
<p class="sg-body">Graphik</p>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body">Inhalt Wachstum.</p></div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-4" role="tabpanel" aria-labelledby="vsf-fundamental-tab-4" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Profitabilität">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Profitabilität <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<div class="sg-score-bar-list sg-score-bar-list--single-score" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state"><strong class="sg-score-bar-label">(9.9)</strong></p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<table class="sg-data-table" aria-label="Profitabilität Kennzahlen" data-component="data-table">
<thead>
<tr>
<th data-component-part="data-table-header-cell">Kennzahl</th>
<th data-component-part="data-table-header-cell">Wert</th>
</tr>
</thead>
<tbody>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">27.5</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">26.4</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PEG Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value sg-score-state--positive" data-component-part="data-table-value-cell">0.35</td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body">
<p class="sg-body">Graphik</p>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body">Inhalt Profitabilität.</p></div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-5" role="tabpanel" aria-labelledby="vsf-fundamental-tab-5" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Stabilität">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Stabilität <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<div class="sg-score-bar-list sg-score-bar-list--single-score" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state"><strong class="sg-score-bar-label">(9.9)</strong></p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--gray" data-component-part="card-body">
<table class="sg-data-table" aria-label="Stabilität Kennzahlen" data-component="data-table">
<thead>
<tr>
<th data-component-part="data-table-header-cell">Kennzahl</th>
<th data-component-part="data-table-header-cell">Wert</th>
</tr>
</thead>
<tbody>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">27.5</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value" data-component-part="data-table-value-cell">26.4</td>
</tr>
<tr>
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PEG Forward <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="data-table"><button class="sg-help-icon sg-data-table__help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></td>
<td class="sg-data-table__value sg-score-state--positive" data-component-part="data-table-value-cell">0.35</td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body">
<p class="sg-body">Graphik</p>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body">Inhalt Stabilität.</p></div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-6" role="tabpanel" aria-labelledby="vsf-fundamental-tab-6" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="TAM">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">TAM <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Der Gesamtmarkt für Datenspeicher wird bis zum Jahr 2030 auf rund 200 Milliarden Dollar geschätzt. Dieses Wachstum wird durch exponentiell steigende Datenmengen angetrieben, wobei Technologien wie Cloud-Computing und das Training künstlicher Intelligenz zentrale Treiber mit hohen jährlichen Zuwachsraten sind. Western Digital adressiert primär den NAND-Flash-Markt, in dem es mit einem Marktanteil von 15 bis 18 Prozent hinter dem Marktführer liegt.</p>
<p class="sg-body">Der Wettbewerb ist in einem Dreier-Oligopol intensiv und verschärft sich durch den Kapazitätsausbau eines chinesischen Konkurrenten. Realistischer Expansionsspielraum für Western Digital wird auf einen Marktanteilsgewinn von 5 bis 10 Prozent geschätzt, angetrieben durch überdurchschnittliches Bit-Wachstum und die positive Nachfrage im KI-Bereich. Der direkt adressierbare Markt konzentriert sich auf Enterprise-SSDs und Cloud-Speicher, da der Markt für Consumer-Festplatten rückläufig ist. Überproportionales Wachstum wäre möglich, wenn das Unternehmen KI-spezifische Speicherlösungen priorisiert, allerdings limitiert Preisdruck die Marge.</p>
</div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-7" role="tabpanel" aria-labelledby="vsf-fundamental-tab-7" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Zyklus">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Zyklus <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body">Inhalt Zyklus.</p></div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-8" role="tabpanel" aria-labelledby="vsf-fundamental-tab-8" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Moat">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Moat <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body">Inhalt Moat.</p></div>
</article>
</div>
<div class="sg-content-block-card-group__panel" id="vsf-fundamental-tab-panel-9" role="tabpanel" aria-labelledby="vsf-fundamental-tab-9" hidden>
<article class="sg-card sg-card--content-card sg-card--overlay-host" data-component="content-card" aria-label="Technologie">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header"><div class="sg-strong">Technologie <span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon"><button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button><span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</span></span></div></div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body">Inhalt Technologie.</p></div>
</article>
</div>
</div>
</div>
<div class="sg-navigation-card-layout">
<div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigation Zurück zur Liste unten">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="./vsf-card-listen-seite.html" data-component="hyperlink">zurück zur Liste</a>
</div>
</div>
</article>
</div>
</div>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
const businessModelToggleButton = document.getElementById('vsf-business-model-toggle');
const businessModelText = document.getElementById('vsf-business-model-text');
if (businessModelToggleButton && businessModelText) {
businessModelToggleButton.addEventListener('click', () => {
const isExpanded = businessModelToggleButton.getAttribute('aria-expanded') === 'true';
const nextExpanded = !isExpanded;
businessModelText.hidden = !nextExpanded;
businessModelToggleButton.setAttribute('aria-expanded', String(nextExpanded));
businessModelToggleButton.textContent = nextExpanded
? 'Geschäftsmodell ausblenden'
: 'Geschäftsmodell anzeigen';
});
}
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
if (!button) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-sandwich-menu-wrap'],
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
});
const tabGroup = document.querySelector('[data-pattern="card-gruppe-mit-tastennavigation"]');
if (tabGroup) {
const tabs = Array.from(tabGroup.querySelectorAll('[role="tab"]'));
const panels = Array.from(tabGroup.querySelectorAll('[role="tabpanel"]'));
const activateTab = (targetTab) => {
tabs.forEach((tab) => {
tab.setAttribute('aria-selected', String(tab === targetTab));
});
panels.forEach((panel) => {
panel.hidden = panel.id !== targetTab.getAttribute('aria-controls');
});
};
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
activateTab(tab);
});
tab.addEventListener('keydown', (event) => {
if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') {
return;
}
event.preventDefault();
const direction = event.key === 'ArrowRight' ? 1 : -1;
const nextIndex = (index + direction + tabs.length) % tabs.length;
const nextTab = tabs[nextIndex];
nextTab.focus();
activateTab(nextTab);
});
});
}
</script>
</body>
</html>
@@ -0,0 +1,69 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF Card Listen Seite Fundamentalanalyse Mobile</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF Fundamentalanalyse Mobile</h1>
<section class="sg-card-list-page" aria-label="VSF Fundamentalanalyse Seite mobil">
<div class="sg-navigation-card-layout">
<div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigation Zurück zur Liste oben">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="./vsf-card-listen-seite.html" data-component="hyperlink">zurück zur Liste</a>
</div>
</div>
</article>
</div>
</div>
<div class="sg-content-cards-group" data-pattern="content-cards-group" aria-label="Fundamentalanalyse Karten Gruppe mobil">
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Fundamentalanalyse Box 1 mobil">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Box 1</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum sapien ut nibh egestas, sed ultrices quam vestibulum. Integer feugiat, sem a iaculis lacinia, augue libero pretium orci, in dictum eros nibh et risus. Fusce sagittis, dolor ut facilisis tincidunt, lorem nisi sodales sem.</p>
</div>
</article>
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Fundamentalanalyse Box 2 mobil">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Box 2</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum sapien ut nibh egestas, sed ultrices quam vestibulum. Integer feugiat, sem a iaculis lacinia, augue libero pretium orci, in dictum eros nibh et risus. Fusce sagittis, dolor ut facilisis tincidunt, lorem nisi sodales sem.</p>
</div>
</article>
<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Fundamentalanalyse Box 3 mobil">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue" data-component-part="card-header">
<div class="sg-strong">Box 3</div>
</div>
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum sapien ut nibh egestas, sed ultrices quam vestibulum. Integer feugiat, sem a iaculis lacinia, augue libero pretium orci, in dictum eros nibh et risus. Fusce sagittis, dolor ut facilisis tincidunt, lorem nisi sodales sem.</p>
</div>
</article>
</div>
<div class="sg-navigation-card-layout">
<div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigation Zurück zur Liste unten">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="./vsf-card-listen-seite.html" data-component="hyperlink">zurück zur Liste</a>
</div>
</div>
</article>
</div>
</div>
</section>
</body>
</html>
+926
View File
@@ -0,0 +1,926 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF Card Listen Seite</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF Card Listen Seite</h1>
<section class="sg-card-list-page" aria-label="VSF Card Listen Seite">
<header class="sg-portal-header" aria-label="Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">ValueStockFinder</p>
<div class="sg-portal-header__menu-wrap sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="default" data-component-context="portal-header" data-pattern-part="portal-header-action">
<button class="sg-interaction-element sg-sandwich-button" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Updates</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Titel</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Gruppen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Listen</button>
</nav>
</div>
</header>
<div class="sg-options-row" aria-label="Optionszeile" data-pattern="options-row">
<div class="sg-options-row__left" data-pattern-part="options-row-primary-actions">
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Sortierung" data-component-part="pulldown-trigger" data-label-base="Sortierung">
Sortierung
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Sortierung" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Sortierungsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 1</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 2</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 3</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 4</span></li>
<li class="sg-pulldown-option sg-pulldown-option--disabled"><span>Menüpunkt 5</span></li>
</ul>
</div>
</div>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Region" data-component-part="pulldown-trigger" data-label-base="Region">
Region
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Region" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Regionsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 1</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 2</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 3</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 4</span></li>
<li class="sg-pulldown-option sg-pulldown-option--disabled"><span>Menüpunkt 5</span></li>
</ul>
</div>
</div>
<div class="sg-search-field-row">
<span class="sg-input-single-line-wrap sg-search-field-input" data-has-value="false" data-component="single-line-input" data-component-context="options-row" data-component-state="inactive-selectable">
<input class="sg-interaction-element sg-input-single-line" type="text" placeholder="Suche" aria-label="Suche">
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-component-part="input-clear-button">×</button>
</span>
<span class="sg-search-result-count sg-table-label" aria-live="polite" data-pattern-part="options-row-search-result-count">0 Treffer</span>
</div>
</div>
<div class="sg-options-row__right" data-pattern-part="options-row-secondary-actions">
<button class="sg-mode-toggle" type="button" data-active="relative" aria-label="Modus Schieber global: relativ aktiv" data-component="mode-toggle" data-component-context="options-row">
<span class="sg-mode-toggle__label" data-component-part="toggle-label">absolut</span>
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
</span>
<span class="sg-mode-toggle__label" data-component-part="toggle-label">relativ</span>
</button>
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="options-row">
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button>
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.
</span>
</span>
</div>
</div>
<div class="sg-transparent-card sg-card-list-page__intro-block" aria-label="Einleitung zur VSF Listenübersicht" data-component="transparent-card">
<div class="sg-card-list-page__title-row">
<h1 class="sg-heading-h1 sg-text-on-dark sg-card-list-page__title">VSF Listenübersicht</h1>
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="layout-card-list-page">
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext zur VSF Listenübersicht anzeigen" data-component-part="help-trigger">?</button>
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
Hilfe zur Listenansicht und zu den Filteroptionen.
</span>
</span>
</div>
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--sixty-width">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer convallis purus sed urna ultricies, id aliquet justo malesuada. Morbi luctus, augue in cursus ultrices, justo lorem posuere mi, at suscipit est turpis vitae ipsum. Praesent posuere nisl a nisl fermentum, nec feugiat odio volutpat. Nam id dictum justo, eget dapibus arcu. Fusce varius justo nec nibh gravida, sed dignissim est tempor.</p>
</div>
<div class="sg-object-card-grid sg-card-list-page__object-grid" aria-label="Company Liste">
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-strong">Netflix, Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<table class="sg-data-table" aria-label="Company Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td data-component-part="data-columns-value-cell">PE: <span class="sg-data-table__value">28.8</span></td>
<td data-component-part="data-columns-reference-cell">PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span></td>
</tr>
<tr>
<td data-component-part="data-columns-value-cell">PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span></td>
<td data-component-part="data-columns-reference-cell"></td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-strong">Netflix, Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<table class="sg-data-table" aria-label="Company Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td data-component-part="data-columns-value-cell">PE: <span class="sg-data-table__value">28.8</span></td>
<td data-component-part="data-columns-reference-cell">PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span></td>
</tr>
<tr>
<td data-component-part="data-columns-value-cell">PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span></td>
<td data-component-part="data-columns-reference-cell"></td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-strong">Netflix, Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<table class="sg-data-table" aria-label="Company Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td data-component-part="data-columns-value-cell">PE: <span class="sg-data-table__value">28.8</span></td>
<td data-component-part="data-columns-reference-cell">PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span></td>
</tr>
<tr>
<td data-component-part="data-columns-value-cell">PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span></td>
<td data-component-part="data-columns-reference-cell"></td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-strong">Netflix, Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<table class="sg-data-table" aria-label="Company Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td data-component-part="data-columns-value-cell">PE: <span class="sg-data-table__value">28.8</span></td>
<td data-component-part="data-columns-reference-cell">PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span></td>
</tr>
<tr>
<td data-component-part="data-columns-value-cell">PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span></td>
<td data-component-part="data-columns-reference-cell"></td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-strong">Netflix, Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<table class="sg-data-table" aria-label="Company Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td data-component-part="data-columns-value-cell">PE: <span class="sg-data-table__value">28.8</span></td>
<td data-component-part="data-columns-reference-cell">PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span></td>
</tr>
<tr>
<td data-component-part="data-columns-value-cell">PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span></td>
<td data-component-part="data-columns-reference-cell"></td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="company-card" aria-label="Company Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="company-card-header">
<div class="sg-strong">Netflix, Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-score">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Score:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--lightgrey" data-pattern-part="company-card-data-columns">
<table class="sg-data-table" aria-label="Company Kennzahlen-Spalten" data-component="data-columns">
<tbody>
<tr>
<td data-component-part="data-columns-value-cell">PE: <span class="sg-data-table__value">28.8</span></td>
<td data-component-part="data-columns-reference-cell">PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span></td>
</tr>
<tr>
<td data-component-part="data-columns-value-cell">PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span></td>
<td data-component-part="data-columns-reference-cell"></td>
</tr>
</tbody>
</table>
</div>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Fundamentalanalyse vom 8.5.2026:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
<div class="sg-score-bar__median-marker" data-component-part="score-median-marker"></div>
</div>
</div>
<div class="sg-company-card__moat-row">
<span class="sg-score-bar-label sg-bar-label sg-company-card__moat-label">Moat:</span>
<span class="sg-bar-label sg-company-card__moat-neutral sg-company-card__moat-value">Maessig</span>
</div>
</div>
<p class="sg-body sg-company-card__summary">
Attraktiv: Exzellente Profitabilität und starkes Wachstum jenseits des Flaggschiffs. Wichtigstes Risiko ist die hohe Abhängigkeit von einem Produkt mit nahendem Patentablauf.
</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="company-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<div class="sg-navigation-card-layout sg-card-list-page__navigation">
<div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">mehr laden</a>
</div>
</div>
</article>
</div>
</div>
</div>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
const updateObjectCardGridRowState = () => {
document.querySelectorAll('.sg-object-card-grid').forEach((grid) => {
const cards = Array.from(grid.querySelectorAll('.sg-object-card'));
grid.classList.remove('sg-object-card-grid--multi-row');
grid.style.removeProperty('--layout-object-card-shared-width');
if (cards.length <= 1) {
return;
}
const firstTop = cards[0].offsetTop;
const hasMultipleRows = cards.some((card) => card.offsetTop !== firstTop);
if (!hasMultipleRows) {
return;
}
const firstRowCards = cards.filter((card) => card.offsetTop === firstTop);
const referenceCard = firstRowCards[0];
if (!referenceCard) {
return;
}
const referenceWidth = referenceCard.getBoundingClientRect().width;
grid.style.setProperty('--layout-object-card-shared-width', `${referenceWidth}px`);
grid.classList.add('sg-object-card-grid--multi-row');
});
};
document.querySelectorAll('.sg-portal-header__tabs').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
if (!button) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
selectableOptions.forEach((option) => {
const optionRow = option.closest('.sg-pulldown-option');
if (!optionRow) {
return;
}
optionRow.classList.toggle(
'sg-pulldown-option--selected',
option.getAttribute('aria-checked') === 'true'
);
});
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
trigger.setAttribute(
'aria-label',
selectedCount > 0 ? `Pulldown ${labelBase} mit aktiver Auswahl` : `Pulldown ${labelBase} ohne aktive Auswahl`
);
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
demo.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
demo.dataset.align = 'left';
}
});
});
document.querySelectorAll('.sg-pulldown-option[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const pulldownDemo = option.closest('.sg-pulldown-demo');
if (pulldownDemo) {
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
otherOption.setAttribute('aria-checked', String(otherOption === option));
});
updatePulldownSelectionState(pulldownDemo);
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
pulldownDemo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
const input = wrap.querySelector('.sg-input-single-line');
const clearButton = wrap.querySelector('.sg-input-clear-button');
if (!input || !clearButton) {
return;
}
const updateState = () => {
wrap.dataset.hasValue = String(input.value.length > 0);
wrap.dataset.componentState = input.value.length > 0 ? 'active' : 'inactive-selectable';
};
input.addEventListener('input', updateState);
clearButton.addEventListener('click', () => {
input.value = '';
updateState();
input.focus();
});
updateState();
});
const mobileBreakpoint = window.matchMedia('(max-width: 767px)');
document.querySelectorAll('.sg-object-card__action').forEach((button) => {
if (button.textContent?.trim() !== 'Fundamentalanalyse') {
return;
}
button.addEventListener('click', () => {
if (mobileBreakpoint.matches) {
window.location.href = './vsf-card-listen-fundamentalanalyse-mobile.html';
return;
}
window.location.href = './vsf-card-listen-fundamentalanalyse-drawer.html';
});
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
if (!event.target.closest('.sg-pulldown-demo')) {
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
}
});
window.addEventListener('load', updateObjectCardGridRowState);
window.addEventListener('resize', updateObjectCardGridRowState);
</script>
</body>
</html>
+507
View File
@@ -0,0 +1,507 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Layout VSF List Card</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF List Card</h1>
<section id="layout-vsf-list-card">
<p class="sg-preview-label">Layout: VSF List Card</p>
<p class="sg-body">Diese Layout-Seite zeigt VSF-spezifische List-Card-Layouts als Grundlage fuer weitere Ausdifferenzierungen.</p>
<h2 class="sg-sub-heading sg-section-h2">Layout 1: Neue Liste anlegen Karte</h2>
<div class="sg-object-card-grid" aria-label="VSF List Card Layout Neue Liste anlegen">
<article class="sg-card sg-object-card" data-pattern="object-group-card" aria-label="Neue Liste anlegen Karte">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-group-card-header">
<div class="sg-strong">Neue Liste anlegen</div>
</header>
<div class="sg-card-segment sg-card-segment--gray sg-object-card__content" data-pattern-part="object-group-card-content">
<div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Formular mit Abschnitten">
<form class="sg-form-sections-card" action="#" method="post" aria-label="Neue Liste anlegen Formular">
<div class="sg-form-sections-card__body" data-pattern-part="form-body">
<section class="sg-form-sections-card__chapter" aria-label="Neue Liste">
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Listentyp</span>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="form" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown--inactive-selectable sg-form-inactive-selectable sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown ohne aktive Auswahl" data-component-part="pulldown-trigger" data-label-base="Listentyp">
Listentyp
</button>
<div class="sg-pulldown-panel" aria-label="Geoeffnetes Pulldown Listentyp" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Listentyp Optionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Watchlist</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Portfolio</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Screening</span></li>
</ul>
</div>
</div>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Name</span>
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
placeholder="Name eingeben"
aria-label="Name"
maxlength="80"
>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Beschreibung</span>
<textarea
class="sg-input-multi-line sg-form-inactive-selectable"
rows="4"
placeholder="Beschreibung eingeben"
aria-label="Beschreibung"
maxlength="350"
></textarea>
</label>
</div>
</section>
</div>
<footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment">
<div class="sg-form-sections-card__actions" data-pattern-part="form-actions">
<button class="sg-interaction-element sg-button sg-button--active sg-form-sections-card__action" type="button">Zuruecksetzen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive sg-form-sections-card__action" type="submit" disabled aria-disabled="true">Liste anlegen</button>
</div>
</footer>
</form>
</div>
</div>
</article>
</div>
<h2 class="sg-sub-heading sg-section-h2">Layout 2: Maximale Listenzahl erreicht</h2>
<div class="sg-object-card-grid" aria-label="VSF List Card Layout maximale Listenzahl erreicht">
<article class="sg-card sg-object-card" data-pattern="object-group-card" aria-label="Maximale Listenzahl erreicht Karte">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-group-card-header">
<div class="sg-strong">Neue Liste anlegen</div>
</header>
<div class="sg-card-segment sg-card-segment--gray sg-object-card__content" data-pattern-part="object-group-card-content">
<div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Formular mit Abschnitten">
<form class="sg-form-sections-card" action="#" method="post" aria-label="Neue Liste anlegen Formular deaktiviert">
<p class="sg-vsf-list-card-limit-note">Maximale Listenanzahl erreicht. Du musst eine Liste loeschen oder dein Abonnement upgraden, um mehr Listen anzulegen.</p>
<div class="sg-form-sections-card__body" data-pattern-part="form-body">
<section class="sg-form-sections-card__chapter" aria-label="Neue Liste">
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Listentyp</span>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="form" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown--disabled sg-form-disabled sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown ohne aktive Auswahl" data-component-part="pulldown-trigger" data-label-base="Listentyp" disabled aria-disabled="true">
Listentyp
</button>
<div class="sg-pulldown-panel" aria-label="Geoeffnetes Pulldown Listentyp" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Listentyp Optionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Watchlist</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Portfolio</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Screening</span></li>
</ul>
</div>
</div>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Name</span>
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--disabled sg-form-disabled"
type="text"
placeholder="Name eingeben"
aria-label="Name"
maxlength="80"
disabled
>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Beschreibung</span>
<textarea
class="sg-input-multi-line sg-form-disabled"
rows="4"
placeholder="Beschreibung eingeben"
aria-label="Beschreibung"
maxlength="350"
disabled
></textarea>
</label>
</div>
</section>
</div>
<footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment">
<div class="sg-form-sections-card__actions" data-pattern-part="form-actions">
<button class="sg-interaction-element sg-button sg-button--inactive sg-form-sections-card__action" type="button" disabled aria-disabled="true">Zuruecksetzen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive sg-button--disabled sg-form-sections-card__action" type="submit" disabled aria-disabled="true">Liste anlegen</button>
</div>
</footer>
</form>
</div>
</div>
</article>
</div>
<h2 class="sg-sub-heading sg-section-h2">Layout 3 - List Card inklusive Lösch- und Editier-Funktion</h2>
<div class="sg-object-card-grid sg-delete-confirmation-pattern sg-delete-confirmation-pattern__stage sg-vsf-list-card-context" data-pattern="overlay-card" data-dialog-open="false" aria-label="VSF List Card Layout List Card">
<article class="sg-card sg-object-card sg-delete-confirmation-pattern__target" data-pattern="object-group-card" aria-label="List Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-group-card-header">
<div class="sg-strong">NAME DER LISTE</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#!" data-overlay-open-dialog="edit">Editieren</a>
<a class="sg-sandwich-menu-link" href="#!" data-overlay-open-dialog="delete">Liste loeschen</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-pattern-part="list-card-placeholder-top">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Medianscore:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-pattern-part="list-card-placeholder-bottom">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__three-column-distributed" aria-label="Company Kennzahlen dreispaltig verteilt" data-pattern-part="company-card-metrics-three-column">
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-left">
PE: <span class="sg-data-table__value">28.8</span>
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-center">
PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span>
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-right">
PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span>
</p>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Median-Subscores:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
</div>
</div>
</div>
<p class="sg-body sg-company-card__summary sg-vsf-list-card__summary">BESCHREIBUNG LISTE</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-pattern-part="list-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Unternehmen ansehen</button>
</div>
</footer>
</article>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Liste editieren" role="dialog" aria-modal="true" aria-labelledby="vsf-list-card-inline-edit-title" data-overlay-dialog="edit" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="vsf-list-card-inline-edit-title"><strong>Liste editieren</strong></p>
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Name</span>
<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" value="NAME DER LISTE" aria-label="Name" data-vsf-edit-input>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Beschreibung</span>
<textarea class="sg-input-multi-line sg-form-inactive-selectable" rows="4" aria-label="Beschreibung" data-vsf-edit-input>BESCHREIBUNG LISTE</textarea>
</label>
</div>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" disabled aria-disabled="true" data-vsf-edit-save>
Speichern
</button>
</div>
</div>
</article>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Löschbestätigung" role="dialog" aria-modal="true" aria-labelledby="vsf-list-card-inline-delete-title" data-overlay-dialog="delete" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="vsf-list-card-inline-delete-title"><strong>Möchtest du NAME DER LISTE wirklich löschen?</strong></p>
<p class="sg-body sg-delete-confirmation-pattern__text">Du kannst das nicht rückgängig machen. Bestätige durch Eingabe von <span class="sg-delete-confirmation-pattern__code">DELETE</span>.</p>
<label class="sg-labeled-input-row sg-delete-confirmation-pattern__input-row">
<span class="sg-label">Bestätigung</span>
<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" placeholder="DELETE" aria-label="Löschbestätigung durch DELETE" data-vsf-delete-confirmation-input>
</label>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" disabled aria-disabled="true" data-vsf-delete-confirmation-submit>
Löschen
</button>
</div>
</div>
</article>
</div>
</section>
<script>
const formCard = document.querySelector('#layout-vsf-list-card .sg-object-card-grid:first-of-type .sg-form-sections-card');
const processButton = formCard?.querySelector('.sg-button--process');
const updateProcessButtonState = () => {
if (!formCard || !processButton) {
return;
}
const hasPulldownSelection = Array.from(formCard.querySelectorAll('[data-pulldown-option]'))
.some((option) => option.getAttribute('aria-checked') === 'true');
const hasTextInput = Array.from(formCard.querySelectorAll('input[type="text"], textarea'))
.some((field) => field.value.trim().length > 0);
const isActive = hasPulldownSelection || hasTextInput;
processButton.disabled = !isActive;
processButton.setAttribute('aria-disabled', String(!isActive));
processButton.classList.toggle('sg-button--process-inactive', !isActive);
};
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
updateProcessButtonState();
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
});
});
document.querySelectorAll('.sg-pulldown-option[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const pulldownDemo = option.closest('.sg-pulldown-demo');
if (!pulldownDemo) {
return;
}
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
otherOption.setAttribute('aria-checked', String(otherOption === option));
});
updatePulldownSelectionState(pulldownDemo);
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
pulldownDemo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
formCard?.querySelectorAll('input[type="text"], textarea').forEach((field) => {
field.addEventListener('input', updateProcessButtonState);
});
updateProcessButtonState();
const editInputs = document.querySelectorAll('[data-vsf-edit-input]');
const editSaveButton = document.querySelector('[data-vsf-edit-save]');
const deleteDialogInput = document.querySelector('[data-vsf-delete-confirmation-input]');
const deleteDialogSubmitButton = document.querySelector('[data-vsf-delete-confirmation-submit]');
if (editInputs.length > 0 && editSaveButton) {
const updateEditSaveState = () => {
const hasInput = Array.from(editInputs).some((field) => field.value.trim().length > 0);
editSaveButton.disabled = !hasInput;
editSaveButton.setAttribute('aria-disabled', String(!hasInput));
editSaveButton.classList.toggle('sg-button--process-inactive', !hasInput);
};
editInputs.forEach((field) => {
field.addEventListener('input', updateEditSaveState);
});
updateEditSaveState();
}
if (deleteDialogInput && deleteDialogSubmitButton) {
const updateDeleteDialogState = () => {
const isValid = deleteDialogInput.value === 'DELETE';
deleteDialogSubmitButton.disabled = !isValid;
deleteDialogSubmitButton.setAttribute('aria-disabled', String(!isValid));
deleteDialogSubmitButton.classList.toggle('sg-button--process-inactive', !isValid);
};
deleteDialogInput.addEventListener('input', updateDeleteDialogState);
updateDeleteDialogState();
}
const closeStageDialogs = (stage) => {
stage.querySelectorAll('.sg-delete-confirmation-pattern__floating-card').forEach((dialog) => {
dialog.hidden = true;
});
stage.dataset.dialogOpen = 'false';
};
document.querySelectorAll('.sg-delete-confirmation-pattern__stage').forEach((stage) => {
closeStageDialogs(stage);
});
document.querySelectorAll('[data-overlay-open-dialog]').forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
const stage = link.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
const target = link.getAttribute('data-overlay-open-dialog');
const dialog = stage.querySelector(`.sg-delete-confirmation-pattern__floating-card[data-overlay-dialog="${target}"]`);
if (!dialog) {
return;
}
closeStageDialogs(stage);
dialog.hidden = false;
stage.dataset.dialogOpen = 'true';
const menuWrap = link.closest('.sg-sandwich-menu-wrap');
const menuButton = menuWrap?.querySelector('.sg-sandwich-button');
if (menuWrap) {
menuWrap.dataset.open = 'false';
}
if (menuButton) {
menuButton.setAttribute('aria-expanded', 'false');
}
});
});
document.querySelectorAll('[data-overlay-dialog-close], [data-vsf-delete-confirmation-submit], [data-vsf-edit-save]').forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
const stage = button.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
closeStageDialogs(stage);
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
const panel = wrap.querySelector('.sg-sandwich-menu-panel');
if (!button) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState || !panel) {
return;
}
wrap.dataset.align = 'right';
const panelRect = panel.getBoundingClientRect();
if (panelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
});
document.addEventListener('click', (event) => {
if (event.target.closest('.sg-pulldown-demo') || event.target.closest('.sg-sandwich-menu-wrap')) {
return;
}
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
});
</script>
</body>
</html>
+597
View File
@@ -0,0 +1,597 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF List Detailseite</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF List Detailseite</h1>
<section class="sg-vsf-list-detail-page" aria-label="VSF List Detailseite">
<div class="sg-tab-button-group sg-vsf-list-detail-page__mobile-tabs" role="tablist" aria-label="Tasten Navigation gross" data-component="tab-navigation" data-component-size="large">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" aria-controls="vsf-list-detail-panel-meldungen" id="vsf-list-detail-tab-meldungen" data-component-part="tab-button" data-vsf-list-detail-tab="meldungen">Meldungen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-list-detail-panel-unternehmen" id="vsf-list-detail-tab-unternehmen" data-component-part="tab-button" data-vsf-list-detail-tab="unternehmen">Unternehmen</button>
</div>
<div class="sg-vsf-list-detail-page__content" data-vsf-list-detail-active="meldungen">
<aside class="sg-vsf-list-detail-page__left-column" aria-label="Benachrichtigungen" role="tabpanel" aria-labelledby="vsf-list-detail-tab-meldungen" id="vsf-list-detail-panel-meldungen" data-vsf-list-detail-panel="meldungen">
<div class="sg-delete-confirmation-pattern sg-vsf-list-detail-page__meldungen-overlay-pattern">
<div class="sg-delete-confirmation-pattern__stage" data-pattern="overlay-card" data-dialog-open="false">
<div class="sg-group-card sg-delete-confirmation-pattern__target" data-component="group-card">
<div class="sg-group-card__header-row">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading">Meldungen</h2>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Meldungsmenü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Meldungsmenü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#!" data-component-part="sandwich-menu-link" data-overlay-open-dialog="meldungen">Meldungen anpassen</a>
</div>
</div>
</div>
<button class="sg-interaction-element sg-button sg-button--active sg-vsf-list-detail-page__mobile-toggle" type="button" data-toggle-target="meldungen" data-collapsed-label="Meldungen einblenden" data-expanded-label="Meldungen ausblenden" aria-expanded="true">
Meldungen ausblenden
</button>
<article class="sg-card sg-vsf-list-detail-page__notification-card" data-component="notification-card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">Details</button>
</div>
</article>
<article class="sg-card sg-vsf-list-detail-page__notification-card" data-component="notification-card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">Details</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-vsf-list-detail-page__notification-card" data-component="notification-card" data-component-context="group-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white" data-component-part="card-header">
<p class="sg-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae velit posuere, posuere mauris eu, tincidunt lorem. Proin gravida sapien in mattis molestie. Sed non risus augue. Fusce sed odio vitae purus porta efficitur. Integer tempor congue sem, a convallis lorem ornare eget. Nam. Aenean.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">Details</button>
</div>
</article>
</div>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Meldungen anpassen" role="dialog" aria-modal="true" aria-labelledby="vsf-meldungen-overlay-title" data-overlay-dialog="meldungen" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="vsf-meldungen-overlay-title"><strong>Wähle, welche Meldungen angezeigt werden sollen</strong></p>
<section class="sg-form-sections-card__chapter" aria-labelledby="vsf-meldungen-kapitel-1">
<h2 id="vsf-meldungen-kapitel-1" class="sg-strong sg-form-sections-card__chapter-title">Meldungen</h2>
<div class="sg-form-sections-card__option-group" aria-label="Meldungsarten">
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
<button class="sg-checkbox-field sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Meldungsart 1" data-vsf-meldungen-checkbox>
<span class="sg-checkbox-field__mark" aria-hidden="true"></span>
</button>
<span>Meldungsart 1</span>
</label>
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
<button class="sg-checkbox-field sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Meldungsart 2" data-vsf-meldungen-checkbox>
<span class="sg-checkbox-field__mark" aria-hidden="true"></span>
</button>
<span>Meldungsart 2</span>
</label>
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
<button class="sg-checkbox-field sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Meldungsart 3" data-vsf-meldungen-checkbox>
<span class="sg-checkbox-field__mark" aria-hidden="true"></span>
</button>
<span>Meldungsart 3</span>
</label>
</div>
</section>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" disabled aria-disabled="true" data-overlay-dialog-close data-vsf-meldungen-save>Speichern</button>
</div>
</div>
</article>
</div>
</div>
</aside>
<div class="sg-vsf-list-detail-page__right-column" aria-label="Objektkarten" role="tabpanel" aria-labelledby="vsf-list-detail-tab-unternehmen" id="vsf-list-detail-panel-unternehmen" data-vsf-list-detail-panel="unternehmen">
<div class="sg-group-card" data-component="group-card">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading">Unternehmen</h2>
<div class="sg-object-card-grid" aria-label="Pattern Object Card Liste">
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
<div class="sg-strong">Alcon Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="object-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="object-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button><button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="object-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button><button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="object-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button><button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="object-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button><button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-object-card" data-pattern="object-card" aria-label="Objekt Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header"><div class="sg-strong">Alcon Inc.</div><div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small"><button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger"><span class="sg-sandwich-button__icon" aria-hidden="true"><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span><span class="sg-sandwich-button__line"></span></span></button><div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel"><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a><a class="sg-sandwich-menu-link" href="#">Menüpunkt</a></div></div></header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content" data-pattern-part="object-card-content">
<p class="sg-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cill.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment" data-pattern-part="object-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button><button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
</div>
</div>
</div>
</div>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
const updateObjectCardGridRowState = () => {
document.querySelectorAll('.sg-object-card-grid').forEach((grid) => {
const cards = Array.from(grid.querySelectorAll('.sg-object-card'));
grid.classList.remove('sg-object-card-grid--multi-row');
grid.style.removeProperty('--layout-object-card-shared-width');
if (cards.length <= 1) {
return;
}
const firstTop = cards[0].offsetTop;
const hasMultipleRows = cards.some((card) => card.offsetTop !== firstTop);
if (!hasMultipleRows) {
return;
}
const firstRowCards = cards.filter((card) => card.offsetTop === firstTop);
const referenceCard = firstRowCards[0];
if (!referenceCard) {
return;
}
const referenceWidth = referenceCard.getBoundingClientRect().width;
grid.style.setProperty('--layout-object-card-shared-width', `${referenceWidth}px`);
grid.classList.add('sg-object-card-grid--multi-row');
});
};
const vsfListDetailPage = document.querySelector('.sg-vsf-list-detail-page');
const vsfListDetailMobileTabs = document.querySelector('.sg-vsf-list-detail-page__mobile-tabs');
const vsfListDetailButtons = vsfListDetailMobileTabs ? Array.from(vsfListDetailMobileTabs.querySelectorAll('.sg-tab-button')) : [];
const vsfListDetailPanels = {
meldungen: document.querySelector('[data-vsf-list-detail-panel="meldungen"]'),
unternehmen: document.querySelector('[data-vsf-list-detail-panel="unternehmen"]'),
};
const vsfListDetailMobileQuery = window.matchMedia('(max-width: 767px)');
const syncVsfListDetailMobileState = (activeKey) => {
const nextActiveKey = activeKey === 'unternehmen' ? 'unternehmen' : 'meldungen';
if (vsfListDetailPage) {
vsfListDetailPage.dataset.vsfListDetailActive = nextActiveKey;
}
vsfListDetailButtons.forEach((button) => {
const isActive = button.dataset.vsfListDetailTab === nextActiveKey;
button.setAttribute('aria-selected', String(isActive));
button.dataset.componentState = isActive ? 'active' : 'inactive';
});
const isMobile = vsfListDetailMobileQuery.matches;
Object.entries(vsfListDetailPanels).forEach(([key, panel]) => {
if (!panel) {
return;
}
panel.hidden = isMobile && key !== nextActiveKey;
panel.setAttribute('aria-hidden', String(isMobile && key !== nextActiveKey));
});
};
if (vsfListDetailMobileTabs) {
vsfListDetailButtons.forEach((button) => {
button.addEventListener('click', () => {
syncVsfListDetailMobileState(button.dataset.vsfListDetailTab || 'meldungen');
});
});
}
const handleVsfListDetailMobileModeChange = () => {
syncVsfListDetailMobileState(vsfListDetailPage?.dataset.vsfListDetailActive || 'meldungen');
};
if (typeof vsfListDetailMobileQuery.addEventListener === 'function') {
vsfListDetailMobileQuery.addEventListener('change', handleVsfListDetailMobileModeChange);
} else if (typeof vsfListDetailMobileQuery.addListener === 'function') {
vsfListDetailMobileQuery.addListener(handleVsfListDetailMobileModeChange);
}
syncVsfListDetailMobileState(vsfListDetailPage?.dataset.vsfListDetailActive || 'meldungen');
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
if (!button) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
document.querySelectorAll('[data-toggle-target="meldungen"]').forEach((button) => {
button.addEventListener('click', () => {
const groupCard = button.closest('.sg-group-card');
if (!groupCard) {
return;
}
const cards = groupCard.querySelectorAll('.sg-vsf-list-detail-page__notification-card');
const isExpanded = button.getAttribute('aria-expanded') === 'true';
const nextExpanded = !isExpanded;
cards.forEach((card) => {
card.classList.toggle('sg-vsf-list-detail-page__notification-card--hidden', !nextExpanded);
card.setAttribute('aria-hidden', String(!nextExpanded));
});
button.setAttribute('aria-expanded', String(nextExpanded));
button.textContent = nextExpanded ? (button.dataset.expandedLabel || 'Meldungen ausblenden') : (button.dataset.collapsedLabel || 'Meldungen einblenden');
});
});
const closeVsfDialog = (stage) => {
if (!stage) {
return;
}
stage.querySelectorAll('[data-overlay-dialog]').forEach((dialog) => {
dialog.hidden = true;
});
stage.dataset.dialogOpen = 'false';
};
document.querySelectorAll('[data-overlay-open-dialog]').forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
const stage = link.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
const target = link.getAttribute('data-overlay-open-dialog');
const dialog = stage.querySelector(`[data-overlay-dialog="${target}"]`);
if (!dialog) {
return;
}
stage.querySelectorAll('[data-overlay-dialog]').forEach((otherDialog) => {
otherDialog.hidden = true;
});
dialog.hidden = false;
stage.dataset.dialogOpen = 'true';
const menuWrap = link.closest('.sg-sandwich-menu-wrap');
const menuButton = menuWrap?.querySelector('.sg-sandwich-button');
if (menuWrap) {
menuWrap.dataset.open = 'false';
}
if (menuButton) {
menuButton.setAttribute('aria-expanded', 'false');
}
});
});
document.querySelectorAll('[data-overlay-dialog-close]').forEach((button) => {
button.addEventListener('click', () => {
const stage = button.closest('.sg-delete-confirmation-pattern__stage');
closeVsfDialog(stage);
});
});
const meldungenSaveButton = document.querySelector('[data-vsf-meldungen-save]');
const meldungenCheckboxes = document.querySelectorAll('[data-vsf-meldungen-checkbox]');
const updateMeldungenSaveState = () => {
if (!meldungenSaveButton) {
return;
}
const hasSelection = Array.from(meldungenCheckboxes).some((checkbox) => checkbox.getAttribute('aria-checked') === 'true');
meldungenSaveButton.disabled = !hasSelection;
meldungenSaveButton.setAttribute('aria-disabled', String(!hasSelection));
meldungenSaveButton.classList.toggle('sg-button--process-inactive', !hasSelection);
};
meldungenCheckboxes.forEach((checkbox) => {
checkbox.addEventListener('click', () => {
if (checkbox.disabled) {
return;
}
const option = checkbox.closest('[data-component="checkbox-field"]');
const nextState = checkbox.getAttribute('aria-checked') !== 'true';
checkbox.setAttribute('aria-checked', String(nextState));
checkbox.classList.toggle('sg-form-active', nextState);
checkbox.classList.toggle('sg-checkbox-field--inactive-selectable', !nextState);
if (option) {
option.setAttribute('data-component-state', nextState ? 'active' : 'inactive-selectable');
}
updateMeldungenSaveState();
});
});
updateMeldungenSaveState();
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
selectableOptions.forEach((option) => {
const optionRow = option.closest('.sg-pulldown-option');
if (!optionRow) {
return;
}
optionRow.classList.toggle(
'sg-pulldown-option--selected',
option.getAttribute('aria-checked') === 'true'
);
});
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
trigger.setAttribute(
'aria-label',
selectedCount > 0 ? `Pulldown ${labelBase} mit aktiver Auswahl` : `Pulldown ${labelBase} ohne aktive Auswahl`
);
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const triggerRect = trigger.getBoundingClientRect();
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.width > triggerRect.width || panelRect.right > window.innerWidth) {
demo.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
demo.dataset.align = 'left';
}
});
});
document.querySelectorAll('.sg-pulldown-option[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const pulldownDemo = option.closest('.sg-pulldown-demo');
if (pulldownDemo) {
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
otherOption.setAttribute('aria-checked', String(otherOption === option));
});
updatePulldownSelectionState(pulldownDemo);
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
pulldownDemo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
const input = wrap.querySelector('.sg-input-single-line');
const clearButton = wrap.querySelector('.sg-input-clear-button');
if (!input || !clearButton) {
return;
}
const updateState = () => {
wrap.dataset.hasValue = String(input.value.length > 0);
wrap.dataset.componentState = input.value.length > 0 ? 'active' : 'inactive-selectable';
};
input.addEventListener('input', updateState);
clearButton.addEventListener('click', () => {
input.value = '';
updateState();
input.focus();
});
updateState();
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
if (!event.target.closest('.sg-pulldown-demo')) {
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
}
if (!event.target.closest('.sg-delete-confirmation-pattern__floating-card') && !event.target.closest('[data-overlay-open-dialog]')) {
document.querySelectorAll('.sg-delete-confirmation-pattern__stage').forEach((stage) => {
if (stage.dataset.dialogOpen === 'true') {
closeVsfDialog(stage);
}
});
}
});
window.addEventListener('load', updateObjectCardGridRowState);
window.addEventListener('resize', updateObjectCardGridRowState);
</script>
</body>
</html>
@@ -0,0 +1,656 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF Listen Übersicht Seite V2</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF Listen Übersicht Seite V2</h1>
<section class="sg-vsf-list-overview-page-v2" aria-label="VSF Listen Übersicht Seite V2">
<article class="sg-portal-header-pattern-variant" aria-label="Portal Header mit Options Row">
<header class="sg-portal-header" aria-label="Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">ValueStockFinder</p>
<div class="sg-portal-header__menu-wrap sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="default" data-component-context="portal-header" data-pattern-part="portal-header-action">
<button class="sg-interaction-element sg-sandwich-button" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Updates</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Titel</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Gruppen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Listen</button>
</nav>
</div>
</header>
<div class="sg-options-row" aria-label="Optionszeile" data-pattern="options-row">
<div class="sg-options-row__left" data-pattern-part="options-row-primary-actions">
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Sortierung" data-component-part="pulldown-trigger" data-label-base="Sortierung">
Sortierung
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Sortierung" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Sortierungsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 1</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 2</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 3</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 4</span></li>
<li class="sg-pulldown-option sg-pulldown-option--disabled"><span>Menüpunkt 5</span></li>
</ul>
</div>
</div>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Region" data-component-part="pulldown-trigger" data-label-base="Region">
Region
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Region" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Regionsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 1</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 2</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 3</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Menüpunkt 4</span></li>
<li class="sg-pulldown-option sg-pulldown-option--disabled"><span>Menüpunkt 5</span></li>
</ul>
</div>
</div>
<div class="sg-search-field-row">
<span class="sg-input-single-line-wrap sg-search-field-input" data-has-value="false" data-component="single-line-input" data-component-context="options-row" data-component-state="inactive-selectable">
<input class="sg-interaction-element sg-input-single-line" type="text" placeholder="Suche" aria-label="Suche">
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-component-part="input-clear-button">×</button>
</span>
<span class="sg-search-result-count sg-table-label" aria-live="polite" data-pattern-part="options-row-search-result-count">0 Treffer</span>
</div>
</div>
<div class="sg-options-row__right" data-pattern-part="options-row-secondary-actions">
<button class="sg-mode-toggle" type="button" data-active="relative" aria-label="Modus Schieber global: relativ aktiv" data-component="mode-toggle" data-component-context="options-row">
<span class="sg-mode-toggle__label" data-component-part="toggle-label">absolut</span>
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
</span>
<span class="sg-mode-toggle__label" data-component-part="toggle-label">relativ</span>
</button>
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="options-row">
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button>
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.
</span>
</span>
</div>
</div>
</article>
<div class="sg-transparent-card sg-vsf-list-overview-page-v2__intro" aria-label="Intro-Bereich" data-component="transparent-card">
<h1 class="sg-heading-h1">Meine Listen</h1>
<div class="sg-text-layout-pattern" data-pattern="text-layout-sechzig-prozent" aria-label="Text Layout 60 Prozent Breite">
<p class="sg-body sg-text-layout-pattern__sample sg-text-layout-pattern__sample--sixty-width" data-pattern-part="text-block-sixty-width">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut a
</p>
</div>
</div>
<div class="sg-object-card-grid" aria-label="VSF Listen Cards Übersicht">
<div class="sg-object-card sg-delete-confirmation-pattern sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-vsf-list-card-context" data-pattern="object-group-card" data-dialog-open="false" aria-label="VSF List Card Layout List Card">
<article class="sg-card sg-delete-confirmation-pattern__target" data-pattern="object-group-card" aria-label="List Card">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkbrown sg-object-card__header" data-pattern-part="object-group-card-header">
<div class="sg-strong">NAME DER LISTE</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#!" data-overlay-open-dialog="edit">Editieren</a>
<a class="sg-sandwich-menu-link" href="#!" data-overlay-open-dialog="delete">Liste loeschen</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-pattern-part="list-card-company-count">
<p class="sg-body"><strong>7 Unternehmen</strong></p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-pattern-part="list-card-placeholder-top">
<div class="sg-score-bar-list sg-score-bar-list--single-score" aria-label="Gesamtscore-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Medianscore:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" role="img" aria-label="Gesamtscore 96 Prozent mit Median-Marker bei 50 Prozent" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
</div>
<p class="sg-bar-label sg-score-state--positive" data-component-part="score-state">attraktiv</p>
</div>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-pattern-part="list-card-placeholder-bottom">
<div class="sg-text-layout-pattern__sample sg-text-layout-pattern__three-column-distributed" aria-label="Company Kennzahlen dreispaltig verteilt" data-pattern-part="company-card-metrics-three-column">
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-left">
PE: <span class="sg-data-table__value">28.8</span>
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-center">
PE forw.: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">23.3</span>
</p>
<p class="sg-body sg-text-layout-pattern__column sg-text-layout-pattern__column--align-right">
PEG: <span class="sg-data-table__value sg-company-card__metric-negative" data-component-state="negative">3.54</span>
</p>
</div>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-object-card__content" data-pattern-part="company-card-content">
<p class="sg-table-label sg-company-card__analysis-title">Median-Subscores:</p>
<div class="sg-score-bar-list sg-company-card__analysis-bars" aria-label="Fundamentalanalyse Score-Balken" data-component="score-bar-list">
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Marktbewertung:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--positive sg-score-bar__value--w96" data-component-part="score-value" data-component-state="positive"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Wachstum:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Profitabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--negative sg-score-bar__value--w35" data-component-part="score-value" data-component-state="negative"></div>
</div>
</div>
<div class="sg-score-bar-item" data-component="score-bar">
<p class="sg-score-bar-label sg-bar-label" data-component-part="score-label">Stabilität:</p>
<div class="sg-score-bar sg-score-bar--marker-mid" data-component-part="score-track">
<div class="sg-score-bar__value sg-score-bar__value--neutral sg-score-bar__value--w64" data-component-part="score-value" data-component-state="neutral"></div>
</div>
</div>
</div>
<p class="sg-body sg-company-card__summary sg-vsf-list-card__summary">BESCHREIBUNG LISTE</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-pattern-part="list-card-actions">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Unternehmen ansehen</button>
</div>
</footer>
</article>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Liste editieren" role="dialog" aria-modal="true" aria-labelledby="vsf-list-card-inline-edit-title" data-overlay-dialog="edit" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="vsf-list-card-inline-edit-title"><strong>Liste editieren</strong></p>
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Name</span>
<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" value="NAME DER LISTE" aria-label="Name" data-vsf-edit-input>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Beschreibung</span>
<textarea class="sg-input-multi-line sg-form-inactive-selectable" rows="4" aria-label="Beschreibung" data-vsf-edit-input>BESCHREIBUNG LISTE</textarea>
</label>
</div>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" disabled aria-disabled="true" data-vsf-edit-save>
Speichern
</button>
</div>
</div>
</article>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Löschbestätigung" role="dialog" aria-modal="true" aria-labelledby="vsf-list-card-inline-delete-title" data-overlay-dialog="delete" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="vsf-list-card-inline-delete-title"><strong>Möchtest du NAME DER LISTE wirklich löschen?</strong></p>
<p class="sg-body sg-delete-confirmation-pattern__text">Du kannst das nicht rückgängig machen. Bestätige durch Eingabe von <span class="sg-delete-confirmation-pattern__code">DELETE</span>.</p>
<label class="sg-labeled-input-row sg-delete-confirmation-pattern__input-row">
<span class="sg-label">Bestätigung</span>
<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" placeholder="DELETE" aria-label="Löschbestätigung durch DELETE" data-vsf-delete-confirmation-input>
</label>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" disabled aria-disabled="true" data-vsf-delete-confirmation-submit>
Löschen
</button>
</div>
</div>
</article>
</div>
<article class="sg-card sg-object-card" data-pattern="object-group-card" aria-label="Neue Liste anlegen Karte">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkbrown sg-object-card__header" data-pattern-part="object-group-card-header">
<div class="sg-strong">Neue Liste anlegen</div>
</header>
<div class="sg-card-segment sg-card-segment--gray sg-object-card__content" data-pattern-part="object-group-card-content">
<div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Formular mit Abschnitten">
<form class="sg-form-sections-card" action="#" method="post" aria-label="Neue Liste anlegen Formular">
<div class="sg-form-sections-card__body" data-pattern-part="form-body">
<section class="sg-form-sections-card__chapter" aria-label="Neue Liste">
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Listentyp</span>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="form" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown--inactive-selectable sg-form-inactive-selectable sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown ohne aktive Auswahl" data-component-part="pulldown-trigger" data-label-base="Listentyp">
Listentyp
</button>
<div class="sg-pulldown-panel" aria-label="Geoeffnetes Pulldown Listentyp" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Listentyp Optionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Watchlist</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Portfolio</span></li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option><span>Screening</span></li>
</ul>
</div>
</div>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Name</span>
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
placeholder="Name eingeben"
aria-label="Name"
maxlength="80"
>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Beschreibung</span>
<textarea
class="sg-input-multi-line sg-form-inactive-selectable"
rows="4"
placeholder="Beschreibung eingeben"
aria-label="Beschreibung"
maxlength="350"
></textarea>
</label>
</div>
</section>
</div>
<footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment">
<div class="sg-form-sections-card__actions" data-pattern-part="form-actions">
<button class="sg-interaction-element sg-button sg-button--active sg-form-sections-card__action" type="button">Zuruecksetzen</button>
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive sg-form-sections-card__action" type="submit" disabled aria-disabled="true">Liste anlegen</button>
</div>
</footer>
</form>
</div>
</div>
</article>
</div>
<main class="sg-vsf-list-overview-page-v2__content" aria-label="Inhaltsbereich">
<section class="sg-vsf-list-overview-page-v2__primary" aria-label="Primärer Bereich"></section>
<aside class="sg-vsf-list-overview-page-v2__secondary" aria-label="Sekundärer Bereich"></aside>
</main>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
selectableOptions.forEach((option) => {
const optionRow = option.closest('.sg-pulldown-option');
if (!optionRow) {
return;
}
optionRow.classList.toggle(
'sg-pulldown-option--selected',
option.getAttribute('aria-checked') === 'true'
);
});
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
trigger.setAttribute(
'aria-label',
selectedCount > 0 ? `Pulldown ${labelBase} mit aktiver Auswahl` : `Pulldown ${labelBase} ohne aktive Auswahl`
);
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
demo.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
demo.dataset.align = 'left';
}
});
});
document.querySelectorAll('.sg-checkbox-field').forEach((checkbox) => {
checkbox.addEventListener('click', (event) => {
event.stopPropagation();
if (checkbox.disabled) {
return;
}
const nextState = checkbox.getAttribute('aria-checked') !== 'true';
checkbox.setAttribute('aria-checked', String(nextState));
const pulldownDemo = checkbox.closest('.sg-pulldown-demo');
if (pulldownDemo) {
updatePulldownSelectionState(pulldownDemo);
pulldownDemo.dataset.open = 'true';
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
}
});
});
document.querySelectorAll('.sg-pulldown-option[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const pulldownDemo = option.closest('.sg-pulldown-demo');
if (pulldownDemo) {
const selectionMode = pulldownDemo.dataset.selectionMode || 'single';
if (selectionMode === 'multiple') {
const nextState = option.getAttribute('aria-checked') !== 'true';
option.setAttribute('aria-checked', String(nextState));
} else {
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
otherOption.setAttribute('aria-checked', String(otherOption === option));
});
}
updatePulldownSelectionState(pulldownDemo);
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (selectionMode === 'multiple') {
pulldownDemo.dataset.open = 'true';
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
} else {
pulldownDemo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
}
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
const input = wrap.querySelector('.sg-input-single-line');
const clearButton = wrap.querySelector('.sg-input-clear-button');
if (!input || !clearButton) {
return;
}
const updateState = () => {
wrap.dataset.hasValue = String(input.value.length > 0);
wrap.dataset.componentState = input.value.length > 0 ? 'active' : 'inactive-selectable';
};
input.addEventListener('input', updateState);
clearButton.addEventListener('click', () => {
input.value = '';
updateState();
input.focus();
});
updateState();
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
if (event.target.closest('.sg-pulldown-demo')) {
return;
}
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
});
const editInputs = document.querySelectorAll('[data-vsf-edit-input]');
const editSaveButton = document.querySelector('[data-vsf-edit-save]');
const deleteDialogInput = document.querySelector('[data-vsf-delete-confirmation-input]');
const deleteDialogSubmitButton = document.querySelector('[data-vsf-delete-confirmation-submit]');
if (editInputs.length > 0 && editSaveButton) {
const updateEditSaveState = () => {
const hasInput = Array.from(editInputs).some((field) => field.value.trim().length > 0);
editSaveButton.disabled = !hasInput;
editSaveButton.setAttribute('aria-disabled', String(!hasInput));
editSaveButton.classList.toggle('sg-button--process-inactive', !hasInput);
};
editInputs.forEach((field) => {
field.addEventListener('input', updateEditSaveState);
});
updateEditSaveState();
}
if (deleteDialogInput && deleteDialogSubmitButton) {
const updateDeleteDialogState = () => {
const isValid = deleteDialogInput.value === 'DELETE';
deleteDialogSubmitButton.disabled = !isValid;
deleteDialogSubmitButton.setAttribute('aria-disabled', String(!isValid));
deleteDialogSubmitButton.classList.toggle('sg-button--process-inactive', !isValid);
};
deleteDialogInput.addEventListener('input', updateDeleteDialogState);
updateDeleteDialogState();
}
const closeStageDialogs = (stage) => {
stage.querySelectorAll('.sg-delete-confirmation-pattern__floating-card').forEach((dialog) => {
dialog.hidden = true;
});
stage.dataset.dialogOpen = 'false';
};
document.querySelectorAll('.sg-delete-confirmation-pattern__stage').forEach((stage) => {
closeStageDialogs(stage);
});
document.querySelectorAll('[data-overlay-open-dialog]').forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
const stage = link.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
const target = link.getAttribute('data-overlay-open-dialog');
const dialog = stage.querySelector(`.sg-delete-confirmation-pattern__floating-card[data-overlay-dialog="${target}"]`);
if (!dialog) {
return;
}
closeStageDialogs(stage);
dialog.hidden = false;
stage.dataset.dialogOpen = 'true';
const menuWrap = link.closest('.sg-sandwich-menu-wrap');
const menuButton = menuWrap?.querySelector('.sg-sandwich-button');
if (menuWrap) {
menuWrap.dataset.open = 'false';
}
if (menuButton) {
menuButton.setAttribute('aria-expanded', 'false');
}
});
});
document.querySelectorAll('[data-overlay-dialog-close], [data-vsf-delete-confirmation-submit], [data-vsf-edit-save]').forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
const stage = button.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
closeStageDialogs(stage);
});
});
const createListForm = document.querySelector('.sg-vsf-list-overview-page-v2 .sg-object-card-grid .sg-form-sections-card');
const createListProcessButton = createListForm?.querySelector('.sg-button--process');
const updateCreateListProcessButtonState = () => {
if (!createListForm || !createListProcessButton) {
return;
}
const hasPulldownSelection = Array.from(createListForm.querySelectorAll('[data-pulldown-option]'))
.some((option) => option.getAttribute('aria-checked') === 'true');
const hasTextInput = Array.from(createListForm.querySelectorAll('input[type="text"], textarea'))
.some((field) => field.value.trim().length > 0);
const isActive = hasPulldownSelection || hasTextInput;
createListProcessButton.disabled = !isActive;
createListProcessButton.setAttribute('aria-disabled', String(!isActive));
createListProcessButton.classList.toggle('sg-button--process-inactive', !isActive);
};
createListForm?.querySelectorAll('input[type="text"], textarea').forEach((field) => {
field.addEventListener('input', updateCreateListProcessButtonState);
});
createListForm?.querySelectorAll('.sg-pulldown-demo__trigger, [data-pulldown-option]').forEach((control) => {
control.addEventListener('click', () => {
setTimeout(updateCreateListProcessButtonState, 0);
});
});
updateCreateListProcessButtonState();
</script>
</body>
</html>
+819
View File
@@ -0,0 +1,819 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide VSF Meldungen</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Layout VSF Meldungen</h1>
<article class="sg-portal-header-pattern-variant" aria-label="Portal Header mit Options Row">
<header class="sg-portal-header" aria-label="Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">ValueStockFinder</p>
<div class="sg-portal-header__menu-wrap sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="default" data-component-context="portal-header" data-pattern-part="portal-header-action">
<button class="sg-interaction-element sg-sandwich-button" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Admin</a>
<a class="sg-sandwich-menu-link" href="#" data-component-part="sandwich-menu-link">Logout</a>
</div>
</div>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Updates</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Titel</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Gruppen</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Listen</button>
</nav>
</div>
</header>
<div class="sg-options-row" aria-label="Optionszeile" data-pattern="options-row">
<div class="sg-options-row__left" data-pattern-part="options-row-primary-actions">
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Sortierung" data-component-part="pulldown-trigger" data-label-base="Sortierung">
Sortierung
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Sortierung" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Sortierungsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 1</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 2</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 3</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 4</span>
</li>
<li class="sg-pulldown-option sg-pulldown-option--disabled">
<span>Menüpunkt 5</span>
</li>
</ul>
</div>
</div>
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-context="options-row" data-component-state="inactive-selectable">
<button class="sg-interaction-element sg-pulldown sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown Region" data-component-part="pulldown-trigger" data-label-base="Region">
Region
</button>
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown Region" data-component-part="pulldown-panel">
<ul class="sg-pulldown-option-list" aria-label="Regionsoptionen">
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 1</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 2</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 3</span>
</li>
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
<span>Menüpunkt 4</span>
</li>
<li class="sg-pulldown-option sg-pulldown-option--disabled">
<span>Menüpunkt 5</span>
</li>
</ul>
</div>
</div>
<div class="sg-search-field-row">
<span class="sg-input-single-line-wrap sg-search-field-input" data-has-value="false" data-component="single-line-input" data-component-context="options-row" data-component-state="inactive-selectable">
<input
class="sg-interaction-element sg-input-single-line"
type="text"
placeholder="Suche"
aria-label="Suche"
>
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-component-part="input-clear-button">×</button>
</span>
<span class="sg-search-result-count sg-table-label" aria-live="polite" data-pattern-part="options-row-search-result-count">0 Treffer</span>
</div>
</div>
<div class="sg-options-row__right" data-pattern-part="options-row-secondary-actions">
<button class="sg-mode-toggle" type="button" data-active="relative" aria-label="Modus Schieber global: relativ aktiv" data-component="mode-toggle" data-component-context="options-row">
<span class="sg-mode-toggle__label" data-component-part="toggle-label">absolut</span>
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
</span>
<span class="sg-mode-toggle__label" data-component-part="toggle-label">relativ</span>
</button>
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon" data-component-context="options-row">
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button>
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.
</span>
</span>
</div>
</div>
<div class="sg-transparent-card sg-vsf-list-detail-page__intro-block sg-portal-header-pattern-variant__next-element" aria-label="Meldungen Titel" data-component="transparent-card">
<h1 class="sg-heading-h1 sg-vsf-list-detail-page__title">Meldungen</h1>
</div>
<section class="sg-vsf-meldungen-layout" aria-label="VSF Meldungen">
<div class="sg-group-card" data-component="group-card" aria-labelledby="vsf-meldungen-updates-heading">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" id="vsf-meldungen-updates-heading">Updates</h2>
<div class="sg-preview-area sg-notifications-pattern" aria-label="Updates Meldungen">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Update Signal Eins</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Aktualisierung mit hoher Priorität zur Illustration.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Update Signal Zwei</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Positive Meldung zur Illustration.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Update Signal Drei</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Weitere Meldung zur Illustration.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
</div>
<div class="sg-navigation-card-layout sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
<div class="sg-group-card" data-component="group-card" aria-labelledby="vsf-meldungen-kaufsignale-heading">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" id="vsf-meldungen-kaufsignale-heading">Kaufsignale</h2>
<div class="sg-preview-area sg-notifications-pattern" aria-label="Kaufsignale Meldungen">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Signal Eins</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Verkaufssignal zur Illustration.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Signal Zwei</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Positives Kaufsignal zur Illustration.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Kaufsignal Signal Drei</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Weitere Signalmeldung zur Illustration.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
</div>
<div class="sg-navigation-card-layout sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
<div class="sg-group-card" data-component="group-card" aria-labelledby="vsf-meldungen-termine-heading">
<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" id="vsf-meldungen-termine-heading">Termine</h2>
<div class="sg-preview-area sg-notifications-pattern" aria-label="Termine Meldungen">
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Termin Signal Eins</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Terminmeldung mit weissem Hintergrund.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Termin Signal Zwei</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Weiterer Termin mit weissem Hintergrund.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body">
<span class="sg-strong">Termin Signal Drei</span>
</p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">
Dritte Terminmeldung mit weissem Hintergrund.
</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
</div>
<div class="sg-navigation-card-layout sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
</section>
<section class="sg-vsf-meldungen-mobile" aria-label="VSF Meldungen für Mobile">
<div class="sg-group-card" data-component="group-card">
<div class="sg-tab-button-group sg-vsf-meldungen-mobile__tabs" role="tablist" aria-label="Tasten Navigation gross" data-component="tab-navigation" data-component-size="large">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" aria-controls="vsf-meldungen-mobile-panel-updates" id="vsf-meldungen-mobile-tab-updates" data-component-part="tab-button">Updates</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-meldungen-mobile-panel-kaufsignale" id="vsf-meldungen-mobile-tab-kaufsignale" data-component-part="tab-button">Kaufsignale</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" aria-controls="vsf-meldungen-mobile-panel-termine" id="vsf-meldungen-mobile-tab-termine" data-component-part="tab-button">Termine</button>
</div>
<div class="sg-vsf-meldungen-mobile__panels">
<div class="sg-vsf-meldungen-mobile__panel" id="vsf-meldungen-mobile-panel-updates" role="tabpanel" aria-labelledby="vsf-meldungen-mobile-tab-updates">
<div class="sg-preview-area sg-notifications-pattern" aria-label="Updates Meldungen Mobile">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Update Signal Eins</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Aktualisierung mit hoher Priorität zur Illustration.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Update Signal Zwei</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Positive Meldung zur Illustration.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Update Signal Drei</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Weitere Meldung zur Illustration.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
</div>
<div class="sg-navigation-card-layout sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
<div class="sg-vsf-meldungen-mobile__panel" id="vsf-meldungen-mobile-panel-kaufsignale" role="tabpanel" aria-labelledby="vsf-meldungen-mobile-tab-kaufsignale" hidden>
<div class="sg-preview-area sg-notifications-pattern" aria-label="Kaufsignale Meldungen Mobile">
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Kaufsignal Signal Eins</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-red sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Verkaufssignal zur Illustration.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-red" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Kaufsignal Signal Zwei</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Positives Kaufsignal zur Illustration.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-green" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Kaufsignal Signal Drei</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-yellow sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Weitere Signalmeldung zur Illustration.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--signal-yellow" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
</div>
<div class="sg-navigation-card-layout sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
<div class="sg-vsf-meldungen-mobile__panel" id="vsf-meldungen-mobile-panel-termine" role="tabpanel" aria-labelledby="vsf-meldungen-mobile-tab-termine" hidden>
<div class="sg-preview-area sg-notifications-pattern" aria-label="Termine Meldungen Mobile">
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Termin Signal Eins</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Terminmeldung mit weissem Hintergrund.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Termin Signal Zwei</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Weiterer Termin mit weissem Hintergrund.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
<article class="sg-card sg-card--notification-white sg-notifications-pattern__card" data-pattern="notification-with-title" data-component="notification-card">
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment sg-notifications-pattern__title-segment" data-component-part="card-header">
<p class="sg-body"><span class="sg-strong">Termin Signal Drei</span></p>
</div>
<div class="sg-card-segment sg-card-segment--header sg-card-segment--white sg-notifications-pattern__text-segment" data-component-part="card-header">
<p class="sg-body">Dritte Terminmeldung mit weissem Hintergrund.</p>
</div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white" data-component-part="card-body">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">zum Unternehmen</button>
</div>
</article>
</div>
<div class="sg-navigation-card-layout sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</section>
</article>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
selectableOptions.forEach((option) => {
const optionRow = option.closest('.sg-pulldown-option');
if (!optionRow) {
return;
}
optionRow.classList.toggle(
'sg-pulldown-option--selected',
option.getAttribute('aria-checked') === 'true'
);
});
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
trigger.setAttribute(
'aria-label',
selectedCount > 0 ? `Pulldown ${labelBase} mit aktiver Auswahl` : `Pulldown ${labelBase} ohne aktive Auswahl`
);
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const triggerRect = trigger.getBoundingClientRect();
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.width > triggerRect.width || panelRect.right > window.innerWidth) {
demo.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
demo.dataset.align = 'left';
}
});
});
document.querySelectorAll('.sg-checkbox-field').forEach((checkbox) => {
checkbox.addEventListener('click', (event) => {
event.stopPropagation();
if (checkbox.disabled) {
return;
}
const nextState = checkbox.getAttribute('aria-checked') !== 'true';
checkbox.setAttribute('aria-checked', String(nextState));
const pulldownDemo = checkbox.closest('.sg-pulldown-demo');
if (pulldownDemo) {
updatePulldownSelectionState(pulldownDemo);
pulldownDemo.dataset.open = 'true';
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
}
});
});
document.querySelectorAll('.sg-pulldown-option[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const pulldownDemo = option.closest('.sg-pulldown-demo');
if (pulldownDemo) {
const selectionMode = pulldownDemo.dataset.selectionMode || 'single';
if (selectionMode === 'multiple') {
const nextState = option.getAttribute('aria-checked') !== 'true';
option.setAttribute('aria-checked', String(nextState));
} else {
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
otherOption.setAttribute('aria-checked', String(otherOption === option));
});
}
updatePulldownSelectionState(pulldownDemo);
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (selectionMode === 'multiple') {
pulldownDemo.dataset.open = 'true';
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
} else {
pulldownDemo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
}
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
const input = wrap.querySelector('.sg-input-single-line');
const clearButton = wrap.querySelector('.sg-input-clear-button');
if (!input || !clearButton) {
return;
}
const updateState = () => {
wrap.dataset.hasValue = String(input.value.length > 0);
wrap.dataset.componentState = input.value.length > 0 ? 'active' : 'inactive-selectable';
};
input.addEventListener('input', updateState);
clearButton.addEventListener('click', () => {
input.value = '';
updateState();
input.focus();
});
updateState();
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
if (event.target.closest('.sg-pulldown-demo')) {
return;
}
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
});
</script>
<script>
const updateNotificationsPatternRowState = () => {
document.querySelectorAll('.sg-notifications-pattern').forEach((grid) => {
const cards = Array.from(grid.querySelectorAll('.sg-notifications-pattern__card'));
grid.classList.remove('sg-notifications-pattern--multi-row');
grid.style.removeProperty('--layout-object-card-shared-width');
if (cards.length <= 1) {
return;
}
const firstTop = cards[0].offsetTop;
const hasMultipleRows = cards.some((card) => card.offsetTop !== firstTop);
if (!hasMultipleRows) {
return;
}
const firstRowCards = cards.filter((card) => card.offsetTop === firstTop);
const referenceCard = firstRowCards[0];
if (!referenceCard) {
return;
}
const referenceWidth = referenceCard.getBoundingClientRect().width;
grid.style.setProperty('--layout-object-card-shared-width', `${referenceWidth}px`);
grid.classList.add('sg-notifications-pattern--multi-row');
});
};
window.addEventListener('load', updateNotificationsPatternRowState);
window.addEventListener('resize', updateNotificationsPatternRowState);
const mobileVsfMeldungen = document.querySelector('.sg-vsf-meldungen-mobile');
if (mobileVsfMeldungen) {
const mobileTabs = Array.from(mobileVsfMeldungen.querySelectorAll('[role="tab"]'));
const mobilePanels = Array.from(mobileVsfMeldungen.querySelectorAll('[role="tabpanel"]'));
const activateMobileTab = (targetTab) => {
mobileTabs.forEach((tab) => {
tab.setAttribute('aria-selected', String(tab === targetTab));
tab.dataset.componentState = tab === targetTab ? 'active' : 'inactive';
});
mobilePanels.forEach((panel) => {
panel.hidden = panel.id !== targetTab.getAttribute('aria-controls');
});
};
mobileTabs.forEach((tab) => {
tab.addEventListener('click', () => {
activateMobileTab(tab);
});
});
const initialTab = mobileTabs.find((tab) => tab.getAttribute('aria-selected') === 'true') || mobileTabs[0];
if (initialTab) {
activateMobileTab(initialTab);
}
}
</script>
</body>
</html>
+283
View File
@@ -0,0 +1,283 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Pattern VSF Portal Header Public</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body>
<h1 class="sg-main-heading">Pattern VSF Portal Header Public</h1>
<section id="pattern-portal-header">
<article class="sg-portal-header-pattern-variant" aria-label="Portal Header ohne Options Row">
<header class="sg-portal-header" aria-label="Portal Header" data-pattern="portal-header">
<div class="sg-portal-header__main" data-pattern-part="portal-header-main">
<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">ValueStockFinder</p>
<div class="sg-portal-header__menu-wrap" data-pattern-part="portal-header-action">
<div class="sg-tab-button-group" role="tablist" aria-label="Anmeldung" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">
Login
</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">
Registrieren
</button>
</div>
</div>
<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">Übersicht</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Features</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Preise</button>
<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Firma der Woche</button>
</nav>
</div>
</header>
<div class="sg-transparent-card sg-portal-header-pattern-variant__next-element" aria-label="Willkommen bei ValueStockFinder" data-component="transparent-card">
<h1 class="sg-heading-h1 sg-text-on-dark">Willkommen bei ValueStockFinder</h1>
</div>
</article>
</section>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs, .sg-portal-header__menu-wrap .sg-tab-button-group').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
document.querySelectorAll('.sg-mode-toggle').forEach((toggle) => {
toggle.addEventListener('click', () => {
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
toggle.dataset.active = nextState;
toggle.dataset.componentState = nextState;
toggle.setAttribute(
'aria-label',
`Modus Schieber global: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
);
});
});
const updatePulldownSelectionState = (demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
if (!trigger || selectableOptions.length === 0) {
return;
}
const selectedCount = Array.from(selectableOptions).filter((option) => {
return option.getAttribute('aria-checked') === 'true';
}).length;
selectableOptions.forEach((option) => {
const optionRow = option.closest('.sg-pulldown-option');
if (!optionRow) {
return;
}
optionRow.classList.toggle(
'sg-pulldown-option--selected',
option.getAttribute('aria-checked') === 'true'
);
});
const labelBase = trigger.dataset.labelBase || 'Auswahl';
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
trigger.classList.toggle('sg-pulldown--selected', selectedCount > 0);
trigger.classList.toggle('sg-form-active', selectedCount > 0);
trigger.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
demo.dataset.componentState = selectedCount > 0 ? 'selected' : 'inactive-selectable';
trigger.setAttribute(
'aria-label',
selectedCount > 0 ? `Pulldown ${labelBase} mit aktiver Auswahl` : `Pulldown ${labelBase} ohne aktive Auswahl`
);
};
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
if (!trigger) {
return;
}
trigger.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = demo.dataset.open !== 'true';
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
otherDemo.dataset.open = 'false';
if (otherTrigger) {
otherTrigger.setAttribute('aria-expanded', 'false');
}
});
demo.dataset.align = 'left';
demo.dataset.open = String(nextState);
trigger.setAttribute('aria-expanded', String(nextState));
if (!nextState) {
return;
}
const panel = demo.querySelector('.sg-pulldown-panel');
if (!panel) {
return;
}
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > window.innerWidth) {
demo.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
demo.dataset.align = 'left';
}
});
});
document.querySelectorAll('.sg-checkbox-field').forEach((checkbox) => {
checkbox.addEventListener('click', (event) => {
event.stopPropagation();
if (checkbox.disabled) {
return;
}
const nextState = checkbox.getAttribute('aria-checked') !== 'true';
checkbox.setAttribute('aria-checked', String(nextState));
const pulldownDemo = checkbox.closest('.sg-pulldown-demo');
if (pulldownDemo) {
updatePulldownSelectionState(pulldownDemo);
pulldownDemo.dataset.open = 'true';
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
}
});
});
document.querySelectorAll('.sg-pulldown-option[data-pulldown-option]').forEach((option) => {
option.addEventListener('click', (event) => {
event.stopPropagation();
const pulldownDemo = option.closest('.sg-pulldown-demo');
if (pulldownDemo) {
const selectionMode = pulldownDemo.dataset.selectionMode || 'single';
if (selectionMode === 'multiple') {
const nextState = option.getAttribute('aria-checked') !== 'true';
option.setAttribute('aria-checked', String(nextState));
} else {
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
otherOption.setAttribute('aria-checked', String(otherOption === option));
});
}
updatePulldownSelectionState(pulldownDemo);
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
if (selectionMode === 'multiple') {
pulldownDemo.dataset.open = 'true';
if (trigger) {
trigger.setAttribute('aria-expanded', 'true');
}
} else {
pulldownDemo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
}
}
});
});
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
window.sgInitHelpIconOverlays({
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
});
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
const input = wrap.querySelector('.sg-input-single-line');
const clearButton = wrap.querySelector('.sg-input-clear-button');
if (!input || !clearButton) {
return;
}
const updateState = () => {
wrap.dataset.hasValue = String(input.value.length > 0);
wrap.dataset.componentState = input.value.length > 0 ? 'active' : 'inactive-selectable';
};
input.addEventListener('input', updateState);
clearButton.addEventListener('click', () => {
input.value = '';
updateState();
input.focus();
});
updateState();
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.sg-sandwich-menu-wrap')) {
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
if (event.target.closest('.sg-pulldown-demo')) {
return;
}
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
});
</script>
</body>
</html>
+111
View File
@@ -0,0 +1,111 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styleguide Registriere dich bei ValueStockFinder</title>
<link rel="stylesheet" href="../styleguide.css">
</head>
<body class="sg-vsf-register-step-1-page">
<h1 class="sg-main-heading">Layout VFS Keycloak Login</h1>
<main class="sg-vsf-register-step-1">
<article class="sg-card sg-object-card sg-object-card--variable-height sg-vsf-register-step-1__card" data-pattern="object-card" aria-label="Sign in">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header" data-pattern-part="object-card-header">
<div class="sg-strong">Welcome back to ValueStockFinder!</div>
</header>
<footer class="sg-card-segment sg-card-segment--gray" aria-label="Sign in form">
<div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Form with sections">
<form class="sg-form-sections-card" action="#" method="post">
<div class="sg-form-sections-card__body" data-pattern-part="form-body">
<h2 class="sg-strong sg-form-sections-card__title">Sign in to your account</h2>
<div class="sg-form-sections-card__field-group">
<label class="sg-labeled-input-row">
<span class="sg-label">Username or email</span>
<span class="sg-input-validation-stack">
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
value="lkn"
aria-label="Username or email"
aria-invalid="true"
aria-describedby="login-identifier-error"
autocomplete="username"
>
<span class="sg-form-validation-text" id="login-identifier-error">Invalid username or password.</span>
</span>
</label>
<label class="sg-labeled-input-row">
<span class="sg-label">Password</span>
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="password"
placeholder="Enter password"
aria-label="Password"
aria-invalid="true"
autocomplete="current-password"
>
</label>
</div>
</div>
<footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment">
<div class="sg-form-sections-card__actions" data-pattern-part="form-actions">
<button class="sg-interaction-element sg-button sg-button--active sg-form-sections-card__action" type="button">Cancel</button>
<button class="sg-interaction-element sg-button sg-button--process sg-form-sections-card__action" type="submit">Sign In</button>
</div>
</footer>
</form>
</div>
</footer>
<footer class="sg-card-segment sg-card-segment--gray" aria-label="Google login from keycoak">
<div class="sg-strong">Or sign in with</div>
<div class="sg-body">google login from keycoak</div>
</footer>
<footer class="sg-card-segment sg-card-segment--gray" aria-label="Already have an account">
<div class="sg-body">
New user? <a class="sg-hyperlink" href="#" data-component="hyperlink">Register</a>.
</div>
</footer>
</article>
</main>
<script src="../scripts/help-icon-overlays.js"></script>
<script>
document.querySelectorAll('.sg-portal-header__tabs, .sg-portal-header__menu-wrap .sg-tab-button-group').forEach((group) => {
group.querySelectorAll('.sg-tab-button').forEach((button) => {
button.addEventListener('click', () => {
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
const isActive = otherButton === button;
otherButton.setAttribute('aria-selected', String(isActive));
otherButton.dataset.componentState = isActive ? 'active' : 'inactive';
});
});
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
});
});
</script>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CSS_FILE="$ROOT_DIR/styleguide.css"
selectors=(
"sg-portal-header"
"sg-options-row"
"sg-card-list-page-drawer__header"
"sg-card-list-page-drawer__content"
)
for selector in "${selectors[@]}"; do
block="$(awk -v selector=".$selector" '
$0 ~ selector"[[:space:]]*\\{" {in_block=1}
in_block {print}
in_block && /}/ {exit}
' "$CSS_FILE")"
if [[ -z "$block" ]]; then
echo "ERROR: selector .$selector not found in styleguide.css"
exit 1
fi
if echo "$block" | rg -n "(padding|padding-inline|padding-left|padding-right|inset|inset-inline)([^\n;]*)([0-9]+px)" >/dev/null; then
echo "ERROR: hardcoded px inset/padding value found in .$selector"
echo "$block"
exit 1
fi
done
echo "OK: no hardcoded px inset values in guarded pattern selectors"
+129
View File
@@ -0,0 +1,129 @@
(function initHelpIconOverlayModule() {
const CLOSE_HANDLERS = {
'.sg-pulldown-demo': (root) => {
root.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
},
'.sg-sandwich-menu-wrap': (root) => {
root.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
},
};
const getViewportWidth = () => {
if (window.visualViewport && typeof window.visualViewport.width === 'number') {
return window.visualViewport.width;
}
return window.innerWidth;
};
const getSafeInsetPx = () => {
const rootStyles = getComputedStyle(document.documentElement);
const spacingSmallRaw = rootStyles.getPropertyValue('--spacing-small').trim();
const rootFontSize = parseFloat(rootStyles.fontSize) || 16;
const spacingSmallValue = parseFloat(spacingSmallRaw);
if (Number.isNaN(spacingSmallValue)) {
return 0;
}
if (spacingSmallRaw.endsWith('rem')) {
return spacingSmallValue * rootFontSize;
}
return spacingSmallValue;
};
const closeAllHelpIcons = (root) => {
root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
wrap.dataset.open = 'false';
if (panel) {
panel.style.removeProperty('transform');
}
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
};
window.sgInitHelpIconOverlays = (options = {}) => {
const root = options.root || document;
const closeOnOpenSelectors = options.closeOnOpenSelectors || [];
const outsideClickIgnoreSelectors = options.outsideClickIgnoreSelectors || [];
root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
if (wrap.dataset.helpIconInit === 'true') {
return;
}
wrap.dataset.helpIconInit = 'true';
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
if (!button || !panel) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
closeAllHelpIcons(root);
closeOnOpenSelectors.forEach((selector) => {
const handler = CLOSE_HANDLERS[selector];
if (handler) {
handler(root);
}
});
if (!nextState) {
return;
}
wrap.dataset.align = 'left';
wrap.dataset.open = 'true';
button.setAttribute('aria-expanded', 'true');
const viewportWidth = getViewportWidth();
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > viewportWidth) {
wrap.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
wrap.dataset.align = 'left';
}
const clampedRect = panel.getBoundingClientRect();
const safeInset = getSafeInsetPx();
let shiftX = 0;
if (clampedRect.right > (viewportWidth - safeInset)) {
shiftX -= clampedRect.right - (viewportWidth - safeInset);
}
if ((clampedRect.left + shiftX) < safeInset) {
shiftX += safeInset - (clampedRect.left + shiftX);
}
if (shiftX !== 0) {
panel.style.transform = `translateX(${shiftX}px)`;
}
});
});
document.addEventListener('click', (event) => {
const isInsideIgnoredZone = ['.sg-help-icon-wrap', ...outsideClickIgnoreSelectors]
.some((selector) => event.target.closest(selector));
if (isInsideIgnoredZone) {
return;
}
closeAllHelpIcons(root);
});
};
})();
@@ -6,19 +6,19 @@ STYLEGUIDE_REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
SOURCE_CSS="$STYLEGUIDE_REPO_ROOT/styleguide.css"
VERSION_FILE="$STYLEGUIDE_REPO_ROOT/VERSION"
PORTAL_REPO_PATH="/Users/mathias/Documents/Dokumente Chouchou/Codebases/WebApp_Aktienberater"
PORTAL_CSS_REL="public/assets/styleguide.upstream.css"
PORTAL_BUILT_CSS_REL="public/assets/styles.css"
PORTAL_META_REL="public/assets/styleguide.upstream.meta.json"
PORTAL_STYLEGUIDE_DOCS_REL="docs/styleguide"
PORTAL_BUILD_SCRIPT_REL="scripts/styleguide/build_styles.sh"
COMMIT_IN_PORTAL="false"
usage() {
cat <<USAGE
Usage:
$(basename "$0") [--portal-repo <path>] [--commit-portal]
$(basename "$0") [--commit-portal]
Options:
--portal-repo <path> Optional override for portal repository root.
--commit-portal Create commit in portal repo after sync.
-h, --help Show this help.
USAGE
@@ -26,10 +26,6 @@ USAGE
while [[ $# -gt 0 ]]; do
case "$1" in
--portal-repo)
PORTAL_REPO_PATH="${2:-}"
shift 2
;;
--commit-portal)
COMMIT_IN_PORTAL="true"
shift
@@ -56,34 +52,94 @@ if [[ ! -f "$VERSION_FILE" ]]; then
exit 1
fi
if [[ ! -d "$PORTAL_REPO_PATH/.git" ]]; then
echo "Portal repo is not a git repository: $PORTAL_REPO_PATH" >&2
flatten_css() {
local source_file="$1"
local source_root="$2"
local output_file="$3"
: > "$output_file"
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*@import[[:space:]]+\"([^\"]+)\"[[:space:]]*\;[[:space:]]*$ ]]; then
local import_path="${BASH_REMATCH[1]}"
local import_abs="$source_root/$import_path"
if [[ ! -f "$import_abs" ]]; then
echo "Imported CSS not found: $import_abs" >&2
exit 1
fi
cat "$import_abs" >> "$output_file"
printf "\n" >> "$output_file"
else
printf "%s\n" "$line" >> "$output_file"
fi
done < "$source_file"
}
build_portal_css() {
local portal_key="$1"
local source_file="$2"
local output_file="$3"
case "$portal_key" in
vsf)
awk '
BEGIN { skip=0 }
/^:root\[data-portal="naurua"\] \{/ { skip=1; next }
skip && /^}/ { skip=0; next }
skip { next }
{ print }
' "$source_file" > "$output_file"
;;
naurua)
awk '
BEGIN { in_override=0 }
/^:root\[data-portal="naurua"\] \{/ { print ":root {"; in_override=1; next }
in_override && /^}/ { print "}"; in_override=0; next }
{ print }
' "$source_file" > "$output_file"
;;
*)
echo "Unknown portal: $portal_key" >&2
exit 1
;;
esac
}
sync_portal() {
local portal_key="$1"
local portal_repo_path="$2"
local portal_css_path="$portal_repo_path/$PORTAL_CSS_REL"
local portal_built_css_path="$portal_repo_path/$PORTAL_BUILT_CSS_REL"
local portal_meta_path="$portal_repo_path/$PORTAL_META_REL"
local portal_styleguide_docs_path="$portal_repo_path/$PORTAL_STYLEGUIDE_DOCS_REL"
local portal_build_script_path="$portal_repo_path/$PORTAL_BUILD_SCRIPT_REL"
local tmp_portal_css
if [[ ! -d "$portal_repo_path/.git" ]]; then
echo "Portal repo is not a git repository: $portal_repo_path" >&2
exit 1
fi
PORTAL_CSS_PATH="$PORTAL_REPO_PATH/$PORTAL_CSS_REL"
PORTAL_META_PATH="$PORTAL_REPO_PATH/$PORTAL_META_REL"
PORTAL_STYLEGUIDE_DOCS_PATH="$PORTAL_REPO_PATH/$PORTAL_STYLEGUIDE_DOCS_REL"
mkdir -p "$(dirname "$portal_css_path")"
mkdir -p "$portal_styleguide_docs_path"
mkdir -p "$(dirname "$PORTAL_CSS_PATH")"
mkdir -p "$PORTAL_STYLEGUIDE_DOCS_PATH"
cp "$SOURCE_CSS" "$PORTAL_CSS_PATH"
tmp_portal_css="$(mktemp)"
build_portal_css "$portal_key" "$TMP_UPSTREAM_CSS" "$tmp_portal_css"
cp "$tmp_portal_css" "$portal_css_path"
rm -f "$tmp_portal_css"
rsync -a --delete \
--exclude ".git/" \
--exclude ".codex/" \
--exclude ".DS_Store" \
--exclude "AGENTS.md" \
--exclude "scripts/" \
"$STYLEGUIDE_REPO_ROOT/" \
"$PORTAL_STYLEGUIDE_DOCS_PATH/"
"$portal_styleguide_docs_path/"
STYLEGUIDE_VERSION="$(tr -d '[:space:]' < "$VERSION_FILE")"
STYLEGUIDE_COMMIT="$(git -C "$STYLEGUIDE_REPO_ROOT" rev-parse --short HEAD)"
SYNCED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
cat > "$PORTAL_META_PATH" <<META
cat > "$portal_meta_path" <<META
{
"styleguideVersion": "$STYLEGUIDE_VERSION",
"styleguideCommit": "$STYLEGUIDE_COMMIT",
@@ -93,19 +149,72 @@ cat > "$PORTAL_META_PATH" <<META
}
META
case "$portal_key" in
vsf)
if [[ ! -f "$portal_build_script_path" ]]; then
echo "Portal build script not found: $portal_build_script_path" >&2
exit 1
fi
bash "$portal_build_script_path"
;;
naurua)
cp "$portal_css_path" "$portal_built_css_path"
;;
esac
if [[ "$COMMIT_IN_PORTAL" == "true" ]]; then
git -C "$PORTAL_REPO_PATH" add -A "$PORTAL_CSS_REL" "$PORTAL_META_REL" "$PORTAL_STYLEGUIDE_DOCS_REL"
if ! git -C "$PORTAL_REPO_PATH" diff --cached --quiet; then
git -C "$PORTAL_REPO_PATH" commit -m "Sync styleguide $STYLEGUIDE_VERSION"
git -C "$PORTAL_REPO_PATH" push
echo "Portal repo synced and pushed."
git -C "$portal_repo_path" add -A \
"$PORTAL_CSS_REL" \
"$PORTAL_BUILT_CSS_REL" \
"$PORTAL_META_REL" \
"$PORTAL_STYLEGUIDE_DOCS_REL"
if ! git -C "$portal_repo_path" diff --cached --quiet; then
git -C "$portal_repo_path" commit -m "Sync styleguide $STYLEGUIDE_VERSION"
git -C "$portal_repo_path" push
echo "$portal_key portal synced and pushed."
else
echo "No changes to commit in portal repo."
echo "No changes to commit in $portal_key portal repo."
fi
else
echo "Portal files updated locally (no commit requested)."
echo "$portal_key portal files updated locally (no commit requested)."
fi
echo "Synced $SOURCE_CSS -> $PORTAL_CSS_PATH"
echo "Metadata written: $PORTAL_META_PATH"
echo "Mirrored styleguide docs: $PORTAL_STYLEGUIDE_DOCS_PATH"
echo "Synced $SOURCE_CSS -> $portal_css_path"
echo "Built portal stylesheet: $portal_built_css_path"
echo "Metadata written: $portal_meta_path"
echo "Mirrored styleguide docs: $portal_styleguide_docs_path"
}
assert_no_unimported_styles() {
local source_file="$1"
local source_root="$2"
local styles_dir="$source_root/styles"
local missing_imports=()
if [[ ! -d "$styles_dir" ]]; then
return 0
fi
while IFS= read -r css_file; do
local rel_path="./styles/$(basename "$css_file")"
if ! grep -Eq "^[[:space:]]*@import[[:space:]]+\"$rel_path\"[[:space:]]*;" "$source_file"; then
missing_imports+=("$rel_path")
fi
done < <(find "$styles_dir" -maxdepth 1 -type f -name '*.css' | sort)
if [[ ${#missing_imports[@]} -gt 0 ]]; then
echo "Unimported CSS module files detected in styles/:" >&2
for file in "${missing_imports[@]}"; do
echo " - $file" >&2
done
echo "Add missing @import lines in $source_file before syncing." >&2
exit 1
fi
}
TMP_UPSTREAM_CSS="$(mktemp)"
trap 'rm -f "$TMP_UPSTREAM_CSS"' EXIT
assert_no_unimported_styles "$SOURCE_CSS" "$STYLEGUIDE_REPO_ROOT"
flatten_css "$SOURCE_CSS" "$STYLEGUIDE_REPO_ROOT" "$TMP_UPSTREAM_CSS"
sync_portal "vsf" "/Users/mathias/Documents/Dokumente Chouchou/Codebases/WebApp_Aktienberater"
sync_portal "naurua" "/Users/mathias/Documents/Dokumente Chouchou/Codebases/erp_naurua"
+50 -4
View File
@@ -19,6 +19,7 @@
<tbody>
<tr><td>surface-card</td><td>color-light-grey</td><td>Grundfläche der Card.</td></tr>
<tr><td>surface-card-body</td><td>color-light-grey</td><td>Fläche im Body-Segment der Card.</td></tr>
<tr><td>surface-card-segment-neutral</td><td>color-light-grey</td><td>Neutrale Segmentfläche für gezielte hellgraue Card-Segmente (z. B. <code>sg-card-segment--gray</code>).</td></tr>
<tr><td>surface-card-header-primary</td><td>color-darkblue</td><td>Primärer Header-Hintergrund.</td></tr>
<tr><td>surface-card-header-alternative</td><td>color-darkgreen</td><td>Alternativer Header-Hintergrund.</td></tr>
<tr><td>surface-card-header-muted</td><td>color-darkbrown</td><td>Zweite alternative Header-Fläche.</td></tr>
@@ -38,6 +39,7 @@
<tr><td>layout-card-body-text-margin</td><td>0</td><td>Textabstand im Card-Body; verhindert zusätzliche Default-Margins.</td></tr>
</tbody>
</table>
<p class="sg-table-label">Verhaltensregel: Für Cards mit ausklappenden Overlays (z. B. Help-Panel, Sandwich-Menü, Pulldown) ist die Komponenten-Variante <code>sg-card--overlay-host</code> zu verwenden, damit Overlays nicht abgeschnitten werden.</p>
<h3 class="sg-sub-heading sg-section-h3">Group Card</h3>
<table class="sg-foundation-table sg-table-label">
@@ -47,6 +49,19 @@
</tbody>
</table>
<h3 class="sg-sub-heading sg-section-h3">Pattern Card Breiten</h3>
<table class="sg-foundation-table sg-table-label">
<thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead>
<tbody>
<tr><td>layout-object-group-card-min-width</td><td>dimension-object-group-card-min-width</td><td>Mindestbreite der Karteninstanzen im Pattern Object Group Card.</td></tr>
<tr><td>layout-object-group-card-max-width</td><td>dimension-object-group-card-max-width</td><td>Maximalbreite der Karteninstanzen im Pattern Object Group Card.</td></tr>
<tr><td>layout-object-group-card-height</td><td>dimension-object-group-card-height</td><td>Fixe Desktop-Höhe der Karteninstanzen im Pattern Object Group Card.</td></tr>
<tr><td>layout-content-card-margin-top-desktop</td><td>dimension-content-card-margin-top-desktop</td><td>Oberer Außenabstand der Content Card auf Desktop.</td></tr>
<tr><td>layout-content-card-margin-top-mobile</td><td>dimension-content-card-margin-top-mobile</td><td>Oberer Außenabstand der Content Card auf Mobile.</td></tr>
<tr><td>layout-notifications-text-segment-fixed-height</td><td>150px</td><td>Fixe Desktop-Höhe des ersten Text-Segments im Pattern Notifications; auf Mobile wird die Höhe wieder auf auto gesetzt.</td></tr>
</tbody>
</table>
<h3 class="sg-sub-heading sg-section-h3">Text Group Box</h3>
<table class="sg-foundation-table sg-table-label">
<thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead>
@@ -55,6 +70,18 @@
<tr><td>text-card-transparent</td><td>color-font-light</td><td>Textfarbe der Text-Group-Box.</td></tr>
</tbody>
</table>
<h3 class="sg-sub-heading sg-section-h3">VSF Drawer Object Card</h3>
<table class="sg-foundation-table sg-table-label">
<thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead>
<tbody>
<tr><td>surface-vsf-drawer-object-card-header</td><td>color-darkblue</td><td>Header-Fläche der VSF-spezifischen Object Card im Drawer.</td></tr>
<tr><td>surface-vsf-drawer-object-card-body</td><td>color-darkblue</td><td>Body-Fläche der VSF-spezifischen Object Card im Drawer.</td></tr>
<tr><td>text-vsf-drawer-object-card-heading</td><td>color-font-light</td><td>Textfarbe der H2-Überschrift im Header der VSF Drawer Object Card.</td></tr>
<tr><td>text-vsf-drawer-object-card-body</td><td>color-font-light</td><td>Textfarbe der Detailinhalte im Body der VSF Drawer Object Card.</td></tr>
<tr><td>layout-vsf-drawer-object-card-column-gap</td><td>spacing-large</td><td>Spaltenabstand des zweispaltigen Textlayouts in der VSF Drawer Object Card.</td></tr>
</tbody>
</table>
</section>
<section id="semantic-interactive">
@@ -92,16 +119,17 @@
<tr><td>text-control-default</td><td>color-font-dark</td><td>Standard-Textfarbe in Controls.</td></tr>
<tr><td>text-control-disabled</td><td>color-dark-grey</td><td>Textfarbe deaktivierter Controls.</td></tr>
<tr><td>surface-input-clear</td><td>color-medium-grey</td><td>Fläche des Clear-Buttons in Inputs.</td></tr>
<tr><td>layout-input-label-width</td><td>dimension-input-label-width</td><td>Desktop-Breite der Label-Spalte für ein- und mehrzeilige Eingabefelder.</td></tr>
<tr><td>layout-input-label-width</td><td>dimension-input-label-width</td><td>Desktop-Breite der Label-Spalte für gruppierte Formularzeilen mit Pulldowns, Slidern, Radio-Feldern, Checkbox-Feldern sowie ein- und mehrzeiligen Eingabefeldern.</td></tr>
<tr><td>layout-input-field-desktop-width</td><td>dimension-input-field-desktop-width</td><td>Fixe Desktop-Breite für ein- und mehrzeilige Eingabefelder.</td></tr>
<tr><td>layout-input-field-max-width</td><td>dimension-input-field-max-width</td><td>Maximale Breite für ein- und mehrzeilige Eingabefelder (ohne Suchfeld).</td></tr>
<tr><td>layout-search-field-width</td><td>dimension-search-field-width</td><td>Fixe Breite des Suchfeld-Inputs.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Pulldown and Menu</h3>
<p class="sg-table-label">Changelog (2026-05-25): Overlay-Layer vereinheitlicht; Pulldowns liegen über Scorebars (Fix Relativmodus).</p>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead><tbody>
<tr><td>surface-pulldown-panel</td><td>color-light-grey</td><td>Fläche geöffneter Pulldown-Panels.</td></tr>
<tr><td>surface-activatable-remove</td><td>surface-control-default</td><td>Fläche des generischen Schließen-Kontrollfelds in aktivierbaren Varianten (Pulldown, Checkbox, Radio, Slider).</td></tr>
<tr><td>surface-activatable-remove</td><td>surface-control-default</td><td>Fläche des Schließen-Kontrollfelds für aktive Filterzeilen innerhalb geöffneter Pulldown-Panel-Formbereiche.</td></tr>
<tr><td>icon-pulldown-chevron</td><td>currentColor-basierte Verlaufsgrafik</td><td>Chevron-Icon für Pulldown-Trigger und Select-Felder; folgt der aktuellen Textfarbe.</td></tr>
<tr><td>layout-pulldown-panel-padding-inline</td><td>compact-interaction-padding-horizontal</td><td>Horizontaler Innenabstand des geöffneten Pulldown-Panels.</td></tr>
<tr><td>layout-pulldown-option-padding-inline</td><td>compact-interaction-padding-horizontal</td><td>Horizontaler Innenabstand der einzelnen Pulldown-Optionen.</td></tr>
@@ -109,15 +137,18 @@
<tr><td>layout-pulldown-chevron-offset</td><td>compact-interaction-padding-horizontal</td><td>Rechter Innenabstand des Chevron-Icons im Pulldown.</td></tr>
<tr><td>layout-pulldown-chevron-reserved-space</td><td>spacing-large</td><td>Reservierte Breite zwischen Pulldown-Text und rechtem Chevron-Bereich.</td></tr>
<tr><td>layout-pulldown-panel-form-mobile-width</td><td>90%</td><td>Zielbreite für Pulldown-Panels mit Formularinhalt auf Mobile; wird durch die Viewport-Kappe begrenzt.</td></tr>
<tr><td>layer-pulldown-panel</td><td>dimension-layer-pulldown-panel</td><td>Layer-Stufe geöffneter Pulldown-Ausklappfelder über übrigen Seiteninhalten.</td></tr>
<tr><td>layout-multiselect-pulldown-panel-desktop-width</td><td>dimension-multiselect-pulldown-panel-desktop-width</td><td>Semantische Obergrenze für die Panelbreite geöffneter Pulldowns; das Panel darf über Triggerbreite wachsen, bleibt aber durch diese Breite und die Viewport-Kappe begrenzt.</td></tr>
<tr><td>surface-menu-panel-portal</td><td>color-light-grey</td><td>Fläche des Sandwich-Menü-Panels für große und kleine Variante.</td></tr>
<tr><td>text-menu-link-portal</td><td>color-font-dark</td><td>Linktextfarbe im Sandwich-Menü für große und kleine Variante.</td></tr>
<tr><td>text-activatable-remove</td><td>text-control-default</td><td>Zeichenfarbe des generischen Schließen-Kontrollfelds in aktivierbaren Varianten.</td></tr>
<tr><td>text-activatable-remove</td><td>text-control-default</td><td>Zeichenfarbe des Schließen-Kontrollfelds für aktive Filterzeilen innerhalb geöffneter Pulldown-Panel-Formbereiche.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Toggle / Checkbox / Radio / Help</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead><tbody>
<tr><td>surface-toggle-track</td><td>color-medium-grey</td><td>Toggle-Track-Fläche.</td></tr>
<tr><td>surface-toggle-handle</td><td>color-darkblue</td><td>Toggle-Handle-Fläche.</td></tr>
<tr><td>text-toggle-label-active</td><td>color-font-light</td><td>Textfarbe des aktiven Toggle-Labels auf der hervorgehobenen Handle-Seite.</td></tr>
<tr><td>layout-mode-toggle-local-height</td><td>compact-interaction-height</td><td>Höhe des Modus Schieber lokal; entspricht dem kompakten Interaktionsmaß.</td></tr>
<tr><td>layout-mode-toggle-local-width-factor</td><td>3</td><td>Breitenfaktor des lokalen Modus-Schiebers relativ zur lokalen Höhe.</td></tr>
<tr><td>layout-mode-toggle-width</td><td>calc(interaction-height * 3.5)</td><td>Standardbreite des Mode-Toggles in regulären Varianten.</td></tr>
@@ -152,11 +183,18 @@
<h3 class="sg-sub-heading sg-section-h3">Score Bar</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead><tbody>
<tr><td>surface-score-bar-track</td><td>color-light-grey</td><td>Hintergrund der Score-Bar.</td></tr>
<tr><td>surface-score-bar-track</td><td>color-medium-grey</td><td>Hintergrund der Score-Bar.</td></tr>
<tr><td>chart-value-positive</td><td>color-signal-green</td><td>Füllfarbe positiver Werte.</td></tr>
<tr><td>chart-value-neutral</td><td>color-signal-yellow</td><td>Füllfarbe neutraler Werte.</td></tr>
<tr><td>chart-value-negative</td><td>color-signal-red</td><td>Füllfarbe negativer Werte.</td></tr>
<tr><td>chart-median-line</td><td>color-font-dark</td><td>Farbe der Median-Markierung.</td></tr>
<tr><td>text-score-state-positive</td><td>chart-value-positive</td><td>Textfarbe positiver Zustandslabels am Gesamtscore-Balken.</td></tr>
<tr><td>text-score-state-warning</td><td>chart-value-neutral</td><td>Textfarbe der warnenden bzw. gelben Zustandslabels am Gesamtscore-Balken.</td></tr>
<tr><td>text-score-state-neutral</td><td>text-score-state-warning</td><td>Alias für die neutrale Zustandsfarbe am Gesamtscore-Balken; bleibt mit dem bestehenden Component-Contract kompatibel.</td></tr>
<tr><td>text-score-state-negative</td><td>chart-value-negative</td><td>Textfarbe negativer Zustandslabels am Gesamtscore-Balken.</td></tr>
<tr><td>layout-score-bar-item-columns</td><td>max-content und 1fr</td><td>Standardspalten der Score-Bar-Zeile: dynamische Labelspalte (längstes Label) plus Balkenspur.</td></tr>
<tr><td>layout-score-bar-item-gap</td><td>spacing-large</td><td>Abstand zwischen Labelspalte und Balkenspur in der Score-Bar-Zeile.</td></tr>
<tr><td>layout-score-bar-item-single-score-columns</td><td>max-content, 1fr und max-content</td><td>Spalten der Score-Bar-Zeile in der Single-Score-Variante: Label, Balken, Zustandslabel.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Bar / Line Chart</h3>
@@ -184,6 +222,14 @@
<tr><td>text-data-table-warning</td><td>color-signal-yellow</td><td>Warnwertfarbe in Tabellenzellen.</td></tr>
<tr><td>text-data-table-help-icon</td><td>color-font-dark</td><td>Textfarbe im Tabellen-Help-Icon.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Data Columns</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck in der Komponente</th></tr></thead><tbody>
<tr><td>surface-data-table</td><td>color-light-grey</td><td>Gesamtfläche der Spaltenliste.</td></tr>
<tr><td>surface-data-table-cell</td><td>color-light-grey</td><td>Fläche von Spaltenzellen.</td></tr>
<tr><td>text-data-table-default</td><td>color-font-dark</td><td>Standard-Textfarbe in Spaltenzellen.</td></tr>
<tr><td>text-data-table-warning</td><td>color-signal-yellow</td><td>Warnwertfarbe in Spaltenzellen.</td></tr>
</tbody></table>
</section>
<section id="semantic-typography">
+6 -1
View File
@@ -13,7 +13,7 @@
<section id="semantic-layouts">
<h2 class="sg-sub-heading sg-section-h2">Layouts</h2>
<h3 class="sg-sub-heading sg-section-h3">Pattern und Seiten-Layouts</h3>
<h3 class="sg-sub-heading sg-section-h3">Generische Layouts</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Layout</th></tr></thead><tbody>
<tr><td>layout-options-row-margin-top</td><td>spacing-small</td><td>Abstand oberhalb der Options Row.</td></tr>
<tr><td>layout-options-row-main-gap</td><td>spacing-large</td><td>Horizontaler Abstand zwischen linker und rechter Aktionsgruppe.</td></tr>
@@ -31,6 +31,11 @@
<tr><td>layout-content-cards-group-gap</td><td>spacing-small</td><td>Abstand zwischen Inhaltsblock-Karten innerhalb der Gruppe.</td></tr>
<tr><td>layout-card-list-drawer-width</td><td>dimension-card-list-drawer-width</td><td>Breite des ausziehbaren Card-Listenbereichs relativ zum Container.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Valuestockfinder Layouts</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Layout</th></tr></thead><tbody>
<tr><td>layout-company-card-analysis-gap-after-moat</td><td>spacing-large</td><td>Vertikaler Abstand zwischen Moat-Zeile und Analyse-Zusammenfassung in der Company Card.</td></tr>
</tbody></table>
</section>
</body>
+60 -9
View File
@@ -22,6 +22,7 @@
<tr><td>font-size-portal-header-brand</td><td>calc(var(--font-size-brand) * 1.1)</td><td>Schriftgröße der Brand im Portal Header (10% größer als Standard-Brand).</td></tr>
<tr><td>text-portal-header-tab</td><td>color-font-light</td><td>Textfarbe nicht aktiver Header-Tabs.</td></tr>
<tr><td>text-portal-header-tab-active</td><td>color-font-dark</td><td>Textfarbe aktiver Header-Tabs.</td></tr>
<tr><td>layout-page-content-inset-inline</td><td>card-segment-padding-horizontal</td><td>Gemeinsamer horizontaler Content-Inset für Portal Header, Options Row und Card-Listen-Drawer-Content (Single Source of Spacing Truth auf Pattern-Ebene).</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Options Row</h3>
@@ -47,16 +48,26 @@
<tr><td>surface-object-card-lower-segment</td><td>color-white</td><td>Hintergrundfläche der unteren zwei Segmente der Object Card.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Multiselektionspulldown</h3>
<h3 class="sg-sub-heading sg-section-h3">Object Group Card</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>surface-multiselect-pulldown</td><td>color-light-grey</td><td>Grundfläche des geöffneten Kennzahlen-Panels.</td></tr>
<tr><td>surface-multiselect-pulldown-shell</td><td>color-light-grey</td><td>Grundfläche der oberen Trigger-/Suche-Zeile.</td></tr>
<tr><td>surface-multiselect-pulldown-control</td><td>surface-control-default</td><td>Alias auf Standard-Control-Fläche innerhalb des Patterns.</td></tr>
<tr><td>surface-multiselect-pulldown-control-selected</td><td>surface-control-active</td><td>Alias auf aktive Control-Fläche innerhalb des Patterns.</td></tr>
<tr><td>text-multiselect-pulldown-default</td><td>text-control-default</td><td>Alias auf Standard-Textfarbe im Pattern.</td></tr>
<tr><td>text-multiselect-pulldown-muted</td><td>text-control-disabled</td><td>Alias auf reduzierte Textfarbe für deaktivierte Zeilen.</td></tr>
<tr><td>layout-multiselect-pulldown-width</td><td>dimension-multiselect-pulldown-width</td><td>Fixe Panelbreite für die geöffnete Desktop-Darstellung.</td></tr>
<tr><td>layout-multiselect-pulldown-row-label-width</td><td>dimension-multiselect-pulldown-row-label-width</td><td>Breite der linken Label-Spalte im Panel.</td></tr>
<tr><td>layout-object-group-card-min-width</td><td>dimension-object-group-card-min-width</td><td>Mindestbreite der einzelnen Karten im Pattern Object Group Card.</td></tr>
<tr><td>layout-object-group-card-max-width</td><td>dimension-object-group-card-max-width</td><td>Maximalbreite der einzelnen Karten im Pattern Object Group Card.</td></tr>
<tr><td>layout-object-group-card-height</td><td>dimension-object-group-card-height</td><td>Fixe Desktop-Höhe der einzelnen Karten im Pattern Object Group Card.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Notifications</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>layout-notifications-card-flex-basis</td><td>dimension-notifications-card-min-width</td><td>Flex-Basis der Notification Card im Notifications-Pattern; entspricht der gemeinsamen Foundation-Mindestbreite und gilt auch in der dokumentierten Variante innerhalb von <code>.sg-group-card</code>.</td></tr>
<tr><td>layout-notifications-card-min-width</td><td>dimension-notifications-card-min-width</td><td>Mindestbreite der Notification Card im Notifications-Pattern; 50px größer als die Object Card und verhindert zu frühes Schrumpfen bei Viewport-Änderungen.</td></tr>
<tr><td>layout-notifications-card-max-width</td><td>layout-object-card-max-width</td><td>Maximalbreite der Notification Card im Notifications-Pattern; begrenzt Wachstum konsistent zur Object-Card-Breite.</td></tr>
<tr><td>layout-notifications-text-segment-fixed-height</td><td>dimension-notifications-text-segment-fixed-height</td><td>Fixe Desktop-Höhe des ersten Text-Segments im Notifications-Pattern; auf Mobile wird die Höhe auf auto gesetzt.</td></tr>
<tr><td>layout-notifications-text-segment-fixed-height-small</td><td>dimension-notifications-text-segment-fixed-height-small</td><td>Fixe Desktop-Höhe des ersten Text-Segments in der Variante <code>Pattern: Notifications small</code>; auf Mobile wird die Höhe auf auto gesetzt.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Company Card</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>text-company-card-data-negative</td><td>chart-value-negative</td><td>Textfarbe für negative Kennzahlenwerte im Data-Columns-Segment der Company Card.</td></tr>
<tr><td>text-company-card-moat-neutral</td><td>chart-value-neutral</td><td>Textfarbe für die neutrale Moat-Ausprägung im Analyse-Segment der Company Card.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Navigation Card</h3>
@@ -74,6 +85,46 @@
<tr><td>surface-card-list-drawer</td><td>color-background-purple</td><td>Fläche des ausziehbaren Card-Listenbereichs.</td></tr>
<tr><td>text-card-list-drawer</td><td>color-font-dark</td><td>Textfarbe im ausziehbaren Card-Listenbereich.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Text Layouts</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>surface-text-layout-preview</td><td>color-light-grey</td><td>Hintergrundfläche der Vorschau-Segmente im Pattern Text Layouts.</td></tr>
<tr><td>layout-text-layout-column-gap</td><td>spacing-large</td><td>Horizontaler Abstand zwischen Textspalten in zwei- und dreispaltigen Varianten.</td></tr>
<tr><td>layout-text-layout-two-column-columns</td><td>repeat(2, minmax(0, 1fr))</td><td>Spaltenraster für die zweispaltige Text-Variante.</td></tr>
<tr><td>layout-text-layout-three-column-columns</td><td>repeat(3, minmax(0, 1fr))</td><td>Spaltenraster für das Pattern Dreispaltig verteilt.</td></tr>
<tr><td>text-align-text-layout-column-left</td><td>left</td><td>Textausrichtung der linken Spalte im Pattern Dreispaltig verteilt.</td></tr>
<tr><td>text-align-text-layout-column-center</td><td>center</td><td>Textausrichtung der mittleren Spalte im Pattern Dreispaltig verteilt.</td></tr>
<tr><td>text-align-text-layout-column-right</td><td>right</td><td>Textausrichtung der rechten Spalte im Pattern Dreispaltig verteilt.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">VSF List Card</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>text-vsf-list-card-limit-note</td><td>color-signal-red</td><td>Hinweistextfarbe für die Meldung bei erreichter maximaler Listenanzahl.</td></tr>
<tr><td>layout-vsf-list-card-summary-offset-block-start</td><td>layout-company-card-analysis-gap-after-moat</td><td>Vertikaler Abstand vor dem Summary-Block in der VSF List Card.</td></tr>
<tr><td>layout-vsf-list-card-delete-confirmation-target-max-width</td><td>layout-object-group-card-max-width</td><td>Maximalbreite der Delete-Confirmation-Zielkarte innerhalb der VSF-List-Card-Demo.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Multiselektions-Pulldown</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>layout-multiselect-pulldown-label-column-width-fallback</td><td>max-content</td><td>Fallback-Breite der gemeinsamen Labelspalte im Panel, bis die längste Labelbreite per Pattern-Logik ermittelt wurde.</td></tr>
</tbody></table>
<h3 class="sg-sub-heading sg-section-h3">Overlay Card</h3>
<table class="sg-foundation-table sg-table-label"><thead><tr><th>Semantischer Token</th><th>Verwendeter Foundation-Token</th><th>Beschreibung Verwendungszweck im Pattern</th></tr></thead><tbody>
<tr><td>surface-delete-confirmation-overlay</td><td>color-light-grey</td><td>Hintergrundfläche des schwebenden Bestätigungsfensters.</td></tr>
<tr><td>surface-delete-confirmation-target-dim-overlay</td><td>color-black</td><td>Overlay-Farbe zur Ausgrauung des Zielobjekts hinter dem Bestätigungsfenster.</td></tr>
<tr><td>text-delete-confirmation-overlay</td><td>color-font-dark</td><td>Textfarbe im Bestätigungsfenster.</td></tr>
<tr><td>layout-delete-confirmation-target-max-width</td><td>35rem</td><td>Maximalbreite der abgedunkelten Ziel-Card in der Pattern-Demo.</td></tr>
<tr><td>layout-delete-confirmation-overlay-width-factor</td><td>0.8</td><td>Breitenfaktor des schwebenden Bestätigungsfensters relativ zur Breite des Zielobjekts (80%).</td></tr>
<tr><td>layout-delete-confirmation-overlay-offset-block-start</td><td>10%</td><td>Vertikaler Abstand des Overlays vom oberen Rand des Zielobjekts, relativ zur Objektgröße.</td></tr>
<tr><td>layout-delete-confirmation-overlay-max-height</td><td>calc(100vh - 10vh)</td><td>Maximalhöhe des Overlays relativ zum Viewport; danach scrollt der Inhalt innerhalb des Overlays.</td></tr>
<tr><td>layout-delete-confirmation-content-gap</td><td>spacing-small</td><td>Vertikaler Abstand zwischen den Inhaltsblöcken im Overlay.</td></tr>
<tr><td>layout-delete-confirmation-actions-gap</td><td>spacing-small</td><td>Horizontaler Abstand zwischen Abbrechen- und Löschen-Button.</td></tr>
<tr><td>layout-delete-confirmation-actions-offset-block-start</td><td>spacing-large</td><td>Zusätzlicher vertikaler Abstand zwischen Bestätigungs-Eingabefeld und Actions-Zeile.</td></tr>
<tr><td>layout-delete-confirmation-label-width</td><td>dimension-input-label-width</td><td>Label-Spaltenbreite der einzeiligen Bestätigungseingabe.</td></tr>
<tr><td>layout-delete-confirmation-target-dim-opacity</td><td>0.5</td><td>Deckkraft der grauen Überlagerung auf dem zu löschenden Objekt (50% ausgegraut).</td></tr>
<tr><td>layer-delete-confirmation-overlay</td><td>50</td><td>Z-Index-Layer des schwebenden Bestätigungsfensters.</td></tr>
</tbody></table>
</section>
</body>
+26 -2545
View File
File diff suppressed because it is too large Load Diff
+320
View File
@@ -0,0 +1,320 @@
/* ========================================================= */
/* Foundations */
/* ========================================================= */
:root {
/* Colors */
--color-darkblue: #4661A9;
--color-midblue: #657FBA;
--color-darkgreen: #4D646E;
--color-darkbrown: #665F57;
--color-light-grey: #E2E5E9;
--color-medium-grey: #CDCFD4;
--color-dark-grey: #7B879D;
--color-black: #000000;
--color-white: #FFFFFF;
--color-process-inactive: #FFAE79;
--color-signal-green: #009101;
--color-signal-yellow: #9C7A00;
--color-signal-red: #9B3B2F;
--color-font-dark: #414959;
--color-font-light: #FFFFFF;
--color-font-hyperlink: #FF6900;
--color-background-purple: #373C4A;
--color-background-purple-light: #656C7D;
--color-transparent: transparent;
/* Semantic component tokens: Cards */
--surface-card: var(--color-light-grey);
--surface-card-body: var(--color-light-grey);
--surface-card-segment-neutral: var(--color-light-grey);
--surface-card-group: var(--color-background-purple-light);
--surface-card-transparent: var(--color-transparent);
--surface-card-header-primary: var(--color-darkblue);
--surface-card-header-alternative: var(--color-darkgreen);
--surface-card-header-muted: var(--color-darkbrown);
--divider-card-segment: var(--color-white);
--text-card-header: var(--color-font-light);
--text-card-body: var(--color-font-dark);
--text-card-transparent: var(--color-font-light);
--layout-card-body-content-justify: flex-start;
--layout-card-segment-content-gap: var(--spacing-small);
/* Semantic component tokens: Interactive elements */
--surface-form-preview: var(--color-light-grey);
--surface-control-default: var(--color-white);
--surface-control-active: var(--color-white);
--surface-control-inactive: var(--color-white);
--surface-control-disabled: var(--color-white);
--surface-button-active: var(--color-medium-grey);
--surface-button-process: var(--color-font-hyperlink);
--surface-button-process-inactive: var(--color-process-inactive);
--surface-button-inactive: var(--color-light-grey);
--surface-tab-selected: var(--color-dark-grey);
--surface-tab-unselected: var(--color-white);
--surface-tab-compact-background: var(--surface-form-preview);
--surface-tab-compact-unselected: var(--color-medium-grey);
--surface-input-clear: var(--color-medium-grey);
--surface-toggle-track: var(--color-medium-grey);
--surface-toggle-handle: var(--color-darkblue);
--surface-menu-panel-portal: var(--color-light-grey);
--surface-help-icon: var(--color-medium-grey);
--surface-help-panel: var(--color-light-grey);
--surface-pulldown-panel: var(--color-light-grey);
--surface-activatable-remove: var(--surface-control-default);
--surface-slider-track: var(--color-medium-grey);
--surface-slider-progress: var(--color-dark-grey);
--surface-slider-thumb: var(--color-dark-grey);
--surface-checkbox-default: var(--color-white);
--surface-checkbox-on-context: var(--color-white);
--surface-radio-default: var(--color-white);
--layout-pulldown-panel-padding-inline: var(--compact-interaction-padding-horizontal);
--layout-pulldown-option-padding-inline: var(--compact-interaction-padding-horizontal);
--layout-pulldown-padding-inline: var(--compact-interaction-padding-horizontal);
--layout-pulldown-chevron-offset: var(--compact-interaction-padding-horizontal);
--layout-tab-navigation-large-padding-inline: var(--interaction-padding-horizontal);
--layout-pulldown-chevron-reserved-space: var(--spacing-large);
--layout-pulldown-panel-form-mobile-width: 90%;
--layer-pulldown-panel: var(--dimension-layer-pulldown-panel);
--layout-multiselect-pulldown-panel-desktop-width: var(--dimension-multiselect-pulldown-panel-desktop-width);
--layout-multiselect-pulldown-label-column-width-fallback: max-content;
--layout-input-label-width: var(--dimension-input-label-width);
--layout-input-field-desktop-width: var(--dimension-input-field-desktop-width);
--layout-input-field-max-width: var(--dimension-input-field-max-width);
--layout-form-input-field-max-width: calc(var(--layout-input-field-max-width) + 100px);
--layout-search-field-width: var(--dimension-search-field-width);
--layout-mode-toggle-local-height: var(--compact-interaction-height);
--layout-mode-toggle-local-width-factor: 3;
--layout-mode-toggle-width: calc(var(--interaction-height) * 3.5);
--layout-help-panel-width: calc(var(--interaction-height) * 8);
--text-control-default: var(--color-font-dark);
--text-control-disabled: var(--color-dark-grey);
--text-button-process: var(--color-font-light);
--text-tab-selected: var(--color-font-light);
--text-tab-unselected: var(--color-dark-grey);
--text-toggle-label-active: var(--color-font-light);
--text-menu-link-portal: var(--color-font-dark);
--text-help-icon: var(--color-font-dark);
--text-help-panel: var(--color-font-dark);
--text-activatable-remove: var(--text-control-default);
--text-hyperlink: var(--color-font-hyperlink);
--icon-pulldown-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M2 2l4 4 4-4' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='square' stroke-linejoin='miter'/%3E%3C/svg%3E");
--icon-sandwich-line-portal: var(--color-font-dark);
--icon-radio-mark: var(--color-font-dark);
/* Semantic component tokens: Charts */
--surface-score-bar-track: var(--color-medium-grey);
--surface-chart-area: var(--color-light-grey);
--chart-value-positive: var(--color-signal-green);
--chart-value-neutral: var(--color-signal-yellow);
--chart-value-negative: var(--color-signal-red);
--chart-value-primary: var(--color-darkblue);
--chart-value-reference: var(--color-medium-grey);
--chart-grid-line: var(--color-medium-grey);
--chart-axis-line: var(--color-font-dark);
--chart-marker-line: var(--color-font-dark);
--chart-median-line: var(--color-font-dark);
--text-chart-default: var(--color-font-dark);
--text-score-state-positive: var(--chart-value-positive);
--text-score-state-warning: var(--chart-value-neutral);
--text-score-state-neutral: var(--text-score-state-warning);
--text-score-state-negative: var(--chart-value-negative);
--layout-score-bar-item-columns: max-content 1fr;
--layout-score-bar-item-gap: var(--spacing-large);
--layout-score-bar-item-single-score-columns: max-content 1fr max-content;
/* Semantic component tokens: Data display */
--surface-data-table: var(--color-light-grey);
--surface-data-table-header: var(--color-light-grey);
--surface-data-table-cell: var(--color-light-grey);
--surface-data-table-help-icon: var(--color-medium-grey);
--text-data-table-default: var(--color-font-dark);
--text-data-table-warning: var(--color-signal-yellow);
--text-data-table-help-icon: var(--color-font-dark);
/* Semantic component tokens: Typography */
--text-typography-preview: var(--color-font-light);
--layout-preview-align-items: flex-start;
/* Semantic pattern tokens: Portal header */
--surface-portal-header: var(--color-darkblue);
--surface-portal-header-tab: var(--color-midblue);
--surface-portal-header-tab-active: var(--color-light-grey);
--text-portal-header-brand: var(--color-font-light);
--font-size-portal-header-brand: calc(var(--font-size-brand) * 1.1);
--text-portal-header-tab: var(--color-font-light);
--text-portal-header-tab-active: var(--color-font-dark);
--layout-page-content-inset-inline: var(--card-segment-padding-horizontal);
--surface-options-row: var(--color-light-grey);
--surface-options-row-control: var(--surface-control-default);
--surface-options-row-control-selected: var(--surface-control-active);
--surface-options-row-input-clear: var(--surface-input-clear);
--surface-options-row-toggle-track: var(--surface-toggle-track);
--surface-options-row-toggle-handle: var(--surface-toggle-handle);
--surface-options-row-help-icon: var(--surface-help-icon);
--surface-options-row-help-panel: var(--surface-help-panel);
--divider-options-row-mobile: var(--color-white);
--text-options-row-default: var(--text-control-default);
--text-options-row-placeholder: var(--text-control-disabled);
--text-options-row-help-icon: var(--color-font-light);
--text-options-row-help-panel: var(--text-help-panel);
--text-options-row-description: var(--color-font-light);
--layout-options-row-margin-top: var(--spacing-small);
--layout-options-row-main-gap: var(--spacing-large);
--layout-options-row-group-gap: var(--spacing-small);
--layout-options-row-mode-toggle-width: var(--dimension-options-row-mode-toggle-width);
--layout-options-row-help-panel-width: var(--dimension-options-row-help-panel-width);
--layout-object-card-min-width: var(--dimension-object-card-min-width);
--layout-object-card-max-width: var(--dimension-object-card-max-width);
--layout-object-card-height: var(--dimension-object-card-height);
--layout-object-card-content-grow: var(--dimension-object-card-content-grow);
--layout-object-card-mobile-width: var(--dimension-object-card-mobile-width);
--layout-object-card-mobile-height: var(--dimension-object-card-mobile-height);
--layout-object-card-desktop-breakpoint: var(--dimension-object-card-desktop-breakpoint);
--layout-content-card-margin-top-desktop: var(--dimension-content-card-margin-top-desktop);
--layout-content-card-margin-top-mobile: var(--dimension-content-card-margin-top-mobile);
--dimension-notifications-card-min-width: 445px;
--layout-notifications-card-flex-basis: var(--dimension-notifications-card-min-width);
--layout-notifications-card-min-width: var(--dimension-notifications-card-min-width);
--layout-notifications-card-max-width: var(--layout-object-card-max-width);
--dimension-notifications-text-segment-fixed-height: 150px;
--dimension-notifications-text-segment-fixed-height-small: 60px;
--layout-notifications-text-segment-fixed-height: var(--dimension-notifications-text-segment-fixed-height);
--layout-notifications-text-segment-fixed-height-small: var(--dimension-notifications-text-segment-fixed-height-small);
--layout-object-group-card-min-width: var(--dimension-object-group-card-min-width);
--layout-object-group-card-max-width: var(--dimension-object-group-card-max-width);
--layout-object-group-card-height: var(--dimension-object-group-card-height);
--surface-object-card-lower-segment: var(--color-white);
--text-company-card-data-negative: var(--chart-value-negative);
--text-company-card-moat-neutral: var(--chart-value-neutral);
--layout-company-card-analysis-gap-after-moat: var(--spacing-large);
--surface-navigation-card: var(--color-white);
--surface-navigation-card-body: var(--color-white);
--surface-content-block-card-title: var(--color-light-grey);
--surface-content-block-card-content: var(--color-white);
--layout-content-cards-group-gap: var(--spacing-small);
--surface-card-list-drawer: var(--color-background-purple);
--text-content-block-card-title: var(--color-font-dark);
--text-content-block-card-content: var(--color-font-dark);
--text-card-list-drawer: var(--color-font-dark);
--layout-card-list-drawer-width: var(--dimension-card-list-drawer-width);
--surface-vsf-drawer-object-card-header: var(--color-darkblue);
--surface-vsf-drawer-object-card-body: var(--color-darkblue);
--text-vsf-drawer-object-card-heading: var(--color-font-light);
--text-vsf-drawer-object-card-body: var(--color-font-light);
--layout-vsf-drawer-object-card-column-gap: var(--spacing-large);
--text-vsf-list-card-limit-note: var(--color-signal-red);
--layout-vsf-list-card-summary-offset-block-start: var(--layout-company-card-analysis-gap-after-moat);
--layout-vsf-list-card-delete-confirmation-target-max-width: var(--layout-object-group-card-max-width);
--surface-text-layout-preview: var(--color-light-grey);
--layout-text-layout-column-gap: var(--spacing-large);
--layout-text-layout-two-column-columns: repeat(2, minmax(0, 1fr));
--layout-text-layout-three-column-columns: repeat(3, minmax(0, 1fr));
--text-align-text-layout-column-left: left;
--text-align-text-layout-column-center: center;
--text-align-text-layout-column-right: right;
--surface-delete-confirmation-overlay: var(--color-light-grey);
--surface-delete-confirmation-target-dim-overlay: var(--color-black);
--text-delete-confirmation-overlay: var(--color-font-dark);
--layout-delete-confirmation-target-max-width: 35rem;
--layout-delete-confirmation-overlay-width-factor: 0.8;
--layout-delete-confirmation-overlay-offset-block-start: 10%;
--layout-delete-confirmation-overlay-max-height: calc(100vh - 10vh);
--layout-delete-confirmation-content-gap: var(--spacing-small);
--layout-delete-confirmation-actions-gap: var(--spacing-small);
--layout-delete-confirmation-actions-offset-block-start: var(--spacing-large);
--layout-delete-confirmation-label-width: var(--dimension-input-label-width);
--layout-delete-confirmation-target-dim-opacity: 0.5;
--layer-delete-confirmation-overlay: 50;
/* Typography */
--font-family-base: "Open Sans", sans-serif;
--font-size-base: 1rem;
--font-size-small: 0.8rem;
--font-size-brand: 1.6rem;
--font-size-h1: 1.8rem;
--font-size-h2: 1.5rem;
--font-weight-regular: 400;
--font-weight-semibold: 600;
--line-height-base: 1.5;
/* Spacing */
--spacing-small: 0.3rem;
--spacing-large: 1rem;
--card-segment-padding-vertical: 0.75rem;
--card-segment-padding-horizontal: 1rem;
--card-segment-padding-horizontal-mobile: 0.5rem;
--interaction-padding-vertical: 0.25rem;
--interaction-padding-horizontal: 1rem;
/* Dimensions */
--interaction-height: 2rem;
--compact-interaction-height: 1.5rem;
--compact-interaction-padding-vertical: 0.15rem;
--compact-interaction-padding-horizontal: 0.75rem;
--small-interaction-element-size: 1.25rem;
--disabled-opacity: 0.7;
--sandwich-line-width: 1.25rem;
--sandwich-line-height: 4px;
--sandwich-line-gap: 3px;
--score-bar-height: 1rem;
--score-marker-width: 6px;
--score-marker-height: calc(var(--score-bar-height) + 2px);
--chart-height-bar: 24rem;
--chart-height-line: 18rem;
--chart-axis-label-column-width: 4rem;
--chart-axis-label-gap: 5px;
--chart-grid-line-width: 1px;
--chart-line-width: 2px;
--chart-label-position-default: 50%;
--dimension-object-card-min-width: 395px;
--dimension-object-card-max-width: 600px;
--dimension-object-card-height: 600px;
--dimension-object-card-content-grow: 1;
--dimension-object-card-mobile-width: 100%;
--dimension-object-card-mobile-height: auto;
--dimension-object-card-desktop-breakpoint: 768px;
--dimension-content-card-margin-top-desktop: 100px;
--dimension-content-card-margin-top-mobile: 1rem;
--dimension-object-group-card-min-width: 450px;
--dimension-object-group-card-max-width: 650px;
--dimension-object-group-card-height: 700px;
--dimension-input-label-width: 9rem;
--dimension-input-field-desktop-width: 400px;
--dimension-input-field-max-width: 600px;
--dimension-search-field-width: 15.3rem;
--dimension-layer-pulldown-panel: 40;
--dimension-multiselect-pulldown-panel-desktop-width: 500px;
--dimension-options-row-mode-toggle-width: 7rem;
--dimension-options-row-help-panel-width: 16rem;
--dimension-card-list-drawer-width: 40%;
--dimension-slider-track-height: 6px;
--dimension-slider-thumb-size: 22px;
--dimension-slider-thumb-offset-top: -8px;
--radius-slider-track: 999px;
/* Radius */
--radius-card: 8px;
--radius-graph-bar: 2px;
--radius-interaction: 4px;
/* Shadows */
--shadow-none: none;
--shadow-overlay: 0 10px 24px rgba(0, 0, 0, 0.22);
--shadow-interaction-inset: none;
/* Borders */
--border-none: none;
--border-control: none;
/* Runtime defaults */
--layout-object-card-shared-width: auto;
--sg-slider-progress: 0%;
--chart-label-position: var(--chart-label-position-default);
}
:root[data-portal="naurua"] {
--color-darkblue: #354A52;
--font-family-base: "Avenir", sans-serif;
}
+96
View File
@@ -0,0 +1,96 @@
/* ========================================================= */
/* Base */
/* ========================================================= */
body {
font-family: var(--font-family-base);
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
color: var(--color-font-dark);
background: var(--color-background-purple);
margin: 0;
padding: var(--spacing-small);
}
@media (max-width: 48rem) {
:root {
--layout-tab-navigation-large-padding-inline: 0.7rem;
}
body {
padding: var(--spacing-small);
}
}
section {
margin-bottom: var(--spacing-large);
}
section + section {
margin-top: var(--spacing-large);
}
.sg-main-heading {
margin: 0 0 var(--spacing-large) 0;
font-family: var(--font-family-base);
font-size: var(--font-size-brand);
font-weight: var(--font-weight-semibold);
line-height: var(--line-height-base);
color: var(--color-font-light);
}
.sg-sub-heading {
margin: 0 0 var(--spacing-large) 0;
font-family: var(--font-family-base);
font-size: var(--font-size-base);
font-weight: var(--font-weight-semibold);
line-height: var(--line-height-base);
}
.sg-text-on-dark {
color: var(--color-font-light);
}
.sg-brand-title {
margin: 0 0 var(--spacing-large) 0;
font-family: var(--font-family-base);
font-size: var(--font-size-brand);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
}
.sg-heading-h1 {
margin: 0 0 calc(var(--spacing-large) - 0.5rem) 0;
font-family: var(--font-family-base);
font-size: var(--font-size-h1);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
}
.sg-heading-h2 {
margin: 0 0 var(--spacing-large) 0;
font-family: var(--font-family-base);
font-size: var(--font-size-h2);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
}
.sg-preview-label {
margin: 0 0 var(--spacing-small) 0;
font-family: var(--font-family-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-semibold);
line-height: var(--line-height-base);
color: var(--color-font-light);
}
.sg-preview-area {
display: inline-flex;
flex-wrap: wrap;
gap: var(--spacing-small);
align-items: var(--layout-preview-align-items);
padding: 0;
border-radius: 0;
background: transparent;
}
+71
View File
@@ -0,0 +1,71 @@
/* ========================================================= */
/* Typography helpers */
/* ========================================================= */
.sg-body,
.sg-strong,
.sg-section-title,
.sg-bar-label,
.sg-table-label,
.sg-table-value {
font-family: var(--font-family-base);
line-height: var(--line-height-base);
}
.sg-body,
.sg-section-title {
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
}
.sg-body {
margin: 0;
}
.sg-body:not(:last-child) {
margin: 0 0 var(--spacing-large) 0;
}
.sg-strong,
.sg-bar-label {
font-size: var(--font-size-base);
font-weight: var(--font-weight-semibold);
}
.sg-table-label {
font-size: var(--font-size-small);
font-weight: var(--font-weight-regular);
}
.sg-table-value {
font-size: var(--font-size-small);
font-weight: var(--font-weight-semibold);
}
.sg-index a {
color: var(--color-font-hyperlink);
}
.sg-index .sg-sub-heading {
color: var(--color-font-light);
}
.sg-foundation-table {
width: 100%;
margin-bottom: var(--spacing-large);
color: var(--color-font-light);
border: 1px solid var(--color-white);
}
.sg-foundation-table th,
.sg-foundation-table td {
color: var(--color-font-light);
border: 1px solid var(--color-white);
vertical-align: top;
}
.sg-section-h2,
.sg-section-h3 {
margin: 0 0 var(--spacing-small) 0;
color: var(--color-font-light);
}
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
/* ========================================================= */
/* Patterns: Portal Header */
/* ========================================================= */
.sg-portal-header {
--surface-tab-selected: var(--surface-portal-header-tab);
--surface-tab-unselected: var(--surface-portal-header-tab-active);
--text-tab-selected: var(--text-portal-header-tab);
--text-tab-unselected: var(--text-portal-header-tab-active);
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-large);
padding:
var(--card-segment-padding-vertical)
var(--layout-page-content-inset-inline);
border: var(--border-none);
border-radius: var(--radius-card);
box-shadow: var(--shadow-none);
background: var(--surface-portal-header);
}
.sg-portal-header--auth-segment {
flex-direction: column;
align-items: stretch;
gap: var(--spacing-small);
}
.sg-portal-header--auth-segment .sg-portal-header__auth-row {
display: flex;
justify-content: flex-end;
width: 100%;
}
.sg-portal-header__main {
display: grid;
flex: 1 1 auto;
grid-template-columns: minmax(0, 1fr) auto;
grid-template-areas:
"brand menu"
"tabs tabs";
gap: var(--spacing-large);
min-width: 0;
}
.sg-portal-header__brand {
grid-area: brand;
margin: 0;
padding-left: 0;
font-size: var(--font-size-portal-header-brand);
color: var(--text-portal-header-brand);
}
.sg-portal-header__tabs {
grid-area: tabs;
width: 100%;
}
.sg-portal-header__menu-wrap {
grid-area: menu;
justify-self: end;
}
.sg-portal-header--auth-segment .sg-portal-header__main {
width: 100%;
}
.sg-portal-header-pattern-variant {
margin-bottom: var(--spacing-large);
}
.sg-portal-header-pattern-variant__label {
margin: 0 0 var(--spacing-small) 0;
}
.sg-portal-header-pattern-variant__next-element {
margin-top: var(--spacing-large);
}
@media (max-width: calc(var(--layout-object-card-desktop-breakpoint) - 1px)) {
.sg-portal-header__main {
gap: var(--spacing-small) var(--spacing-large);
}
}
@media (max-width: 48rem) {
.sg-portal-header__brand {
font-size: calc(var(--font-size-portal-header-brand) * 0.8);
}
}
+164
View File
@@ -0,0 +1,164 @@
/* ========================================================= */
/* Patterns: Options Row */
/* ========================================================= */
.sg-options-row {
--surface-control-default: var(--surface-options-row-control);
--surface-control-active: var(--surface-options-row-control-selected);
--surface-input-clear: var(--surface-options-row-input-clear);
--surface-toggle-track: var(--surface-options-row-toggle-track);
--surface-toggle-handle: var(--surface-options-row-toggle-handle);
--surface-help-icon: var(--surface-options-row-help-icon);
--surface-help-panel: var(--surface-options-row-help-panel);
--text-control-default: var(--text-options-row-default);
--text-control-disabled: var(--text-options-row-placeholder);
--text-help-icon: var(--text-options-row-help-icon);
--text-help-panel: var(--text-options-row-help-panel);
--layout-mode-toggle-width: var(--layout-options-row-mode-toggle-width);
--layout-help-panel-width: var(--layout-options-row-help-panel-width);
margin-top: var(--layout-options-row-margin-top);
display: flex;
justify-content: space-between;
gap: var(--layout-options-row-main-gap);
padding:
var(--card-segment-padding-vertical)
var(--layout-page-content-inset-inline);
border: var(--border-none);
border-radius: var(--radius-card);
box-shadow: var(--shadow-none);
background: var(--surface-options-row);
}
.sg-options-row--left-only {
justify-content: flex-start;
}
.sg-options-row__left,
.sg-options-row__right {
display: flex;
flex-wrap: wrap;
gap: var(--layout-options-row-group-gap);
align-items: center;
}
.sg-options-row__left {
justify-content: flex-start;
}
.sg-options-row__right {
justify-content: flex-end;
flex-wrap: nowrap;
margin-left: auto;
}
.sg-options-row__left > .sg-search-field-row {
flex: 0 0 auto;
}
@media (max-width: 48rem) {
.sg-options-row {
flex-direction: column;
gap: 0;
padding: 0;
}
.sg-options-row__right,
.sg-options-row__left {
padding:
var(--card-segment-padding-vertical)
var(--card-segment-padding-horizontal);
}
.sg-options-row__right {
order: 1;
justify-content: flex-end;
flex-wrap: nowrap;
margin-left: 0;
}
.sg-options-row__left {
order: 2;
box-shadow: inset 0 1px 0 var(--divider-options-row-mobile);
}
.sg-options-row--left-only {
flex-direction: row;
gap: var(--layout-options-row-main-gap);
padding:
var(--card-segment-padding-vertical)
var(--layout-page-content-inset-inline);
}
.sg-options-row--left-only .sg-options-row__left {
order: 0;
padding: 0;
box-shadow: none;
}
.sg-options-row__left > .sg-pulldown-demo,
.sg-options-row__left > .sg-input-single-line-wrap,
.sg-options-row__left > .sg-search-field-row {
flex: 1 1 calc(50% - var(--layout-options-row-group-gap));
min-width: 0;
}
.sg-options-row__left > .sg-search-field-row {
flex: 0 0 auto;
}
.sg-options-row__left > .sg-input-single-line-wrap .sg-input-single-line,
.sg-options-row__left > .sg-pulldown-demo .sg-pulldown {
width: 100%;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-pulldown-panel {
width: min(
var(--layout-pulldown-panel-form-mobile-width),
calc(100vw - (2 * var(--spacing-large)))
);
min-width: 0;
max-width: calc(100vw - (2 * var(--spacing-large)));
}
.sg-options-row .sg-pulldown-panel .sg-form-sections-card-wrapper,
.sg-options-row .sg-pulldown-panel .sg-form-sections-card {
min-width: 0;
width: 100%;
max-width: 100%;
}
.sg-pulldown-panel .sg-slider-row[data-activatable="true"] {
display: flex;
flex-wrap: wrap;
align-items: center;
column-gap: var(--spacing-large);
row-gap: var(--spacing-small);
}
.sg-pulldown-panel .sg-slider-row[data-activatable="true"] .sg-label {
min-width: 100%;
flex: 0 0 100%;
}
.sg-pulldown-panel .sg-slider-row[data-activatable="true"] .sg-slider {
min-width: 0;
max-width: 100%;
width: 100%;
flex: 1 1 0;
}
.sg-pulldown-panel .sg-slider-row[data-activatable="true"] .sg-slider-value {
min-width: calc(var(--interaction-height) * 1.25);
align-self: center;
white-space: nowrap;
flex: 0 0 auto;
}
.sg-pulldown-panel__row {
grid-template-columns: minmax(0, 1fr) var(--interaction-height);
}
.sg-pulldown-panel__label {
grid-column: 1 / -1;
}
}
+94
View File
@@ -0,0 +1,94 @@
/* ========================================================= */
/* Patterns: Object Card */
/* ========================================================= */
.sg-object-card-grid {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-small);
align-items: flex-start;
width: 100%;
}
.sg-object-card {
display: flex;
flex-direction: column;
flex: 1 1 var(--layout-object-card-min-width);
min-width: var(--layout-object-card-min-width);
max-width: var(--layout-object-card-max-width);
height: var(--layout-object-card-height);
}
.sg-object-card-grid.sg-object-card-grid--multi-row .sg-object-card {
flex: 0 0 var(--layout-object-card-shared-width);
width: var(--layout-object-card-shared-width);
}
@media (max-width: 767px) {
.sg-object-card {
width: var(--layout-object-card-mobile-width);
min-width: 0;
max-width: none;
height: var(--layout-object-card-mobile-height);
}
.sg-object-card[data-pattern="object-group-card"] {
flex-basis: 100%;
width: 100%;
min-width: 0;
max-width: none;
}
}
.sg-object-card__content {
flex: var(--layout-object-card-content-grow) 1 auto;
display: flex;
flex-direction: column;
justify-content: flex-start;
background: var(--color-white);
}
.sg-object-card__header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.sg-object-card__actions {
display: flex;
gap: var(--spacing-small);
width: 100%;
margin-top: 0;
}
.sg-object-card__action {
flex: 1 1 0;
min-width: 0;
}
.sg-object-card--variable-height {
height: auto;
}
.sg-object-card--content-basic {
width: min(70vw, var(--layout-object-card-max-width));
margin-inline: auto;
height: auto;
}
.sg-object-card-content-basic {
margin-top: var(--layout-content-card-margin-top-desktop);
}
@media (max-width: 767px) {
.sg-object-card--content-basic {
width: var(--layout-object-card-mobile-width);
min-width: 0;
max-width: none;
}
.sg-object-card-content-basic {
margin-top: var(--layout-content-card-margin-top-mobile);
}
}
+76
View File
@@ -0,0 +1,76 @@
/* ========================================================= */
/* Patterns: Object Group Card */
/* ========================================================= */
.sg-object-group-card__actions {
margin-top: auto;
}
.sg-object-card[data-pattern="object-group-card"] {
flex: 1 1 var(--layout-object-group-card-min-width);
min-width: var(--layout-object-group-card-min-width);
max-width: var(--layout-object-group-card-max-width);
height: var(--layout-object-group-card-height);
}
.sg-list-group-card--height-600 .sg-object-card[data-pattern="object-group-card"] {
height: var(--layout-object-card-height);
}
@media (max-width: 767px) {
.sg-object-card[data-pattern="object-group-card"] {
height: auto;
}
.sg-list-group-card--height-600 .sg-object-card[data-pattern="object-group-card"] {
height: auto;
}
}
.sg-object-group-card__hint {
color: var(--color-font-light);
}
.sg-company-card__header-title {
display: inline-flex;
align-items: center;
gap: var(--spacing-large);
min-width: 0;
}
.sg-company-card__header-star {
display: inline-block;
flex: 0 0 auto;
inline-size: 1em;
block-size: 1em;
background: url("../assets/icons/star-filled-white.svg") no-repeat center / contain;
}
.sg-company-card__metric-negative {
color: var(--text-company-card-data-negative);
}
.sg-company-card__analysis-title {
margin: 0;
}
.sg-company-card__analysis-bars {
margin-top: 0;
}
.sg-company-card__moat-row {
display: contents;
}
.sg-company-card__moat-value {
justify-self: start;
text-align: left;
}
.sg-company-card__moat-neutral {
color: var(--text-company-card-moat-neutral);
}
.sg-company-card__summary {
margin: 0;
}
+4
View File
@@ -0,0 +1,4 @@
/* ========================================================= */
/* Patterns: Navigation Card */
/* ========================================================= */
+349
View File
@@ -0,0 +1,349 @@
/* ========================================================= */
/* Patterns: Formular mit Abschnitten */
/* ========================================================= */
.sg-form-sections-card {
--layout-form-sections-label-column-width: var(--layout-input-label-width);
--layout-form-sections-interaction-indent: calc(
var(--layout-form-sections-label-column-width) + var(--spacing-large)
);
display: flex;
flex-direction: column;
width: 100%;
background: var(--surface-form-preview);
min-width: min(
100%,
calc(var(--layout-form-sections-label-column-width) + var(--spacing-small) + var(--layout-input-field-desktop-width))
);
max-width: calc(
var(--layout-form-sections-label-column-width) + var(--spacing-small) + var(--layout-form-input-field-max-width)
);
}
.sg-form-sections-card-wrapper {
display: flex;
justify-content: center;
width: 100%;
height: auto;
}
.sg-form-sections-card__body {
padding: 0;
}
.sg-form-sections-card__title {
margin: 0 0 var(--spacing-large) 0;
}
.sg-form-sections-card__actions-segment {
margin-top: var(--spacing-large);
padding: 0;
}
.sg-form-sections-card__chapter + .sg-form-sections-card__chapter {
margin-top: calc(var(--spacing-large) * 2);
}
.sg-form-sections-card__chapter-title,
.sg-form-sections-card__sentence {
margin: 0;
}
.sg-form-sections-card__sentence {
margin-top: var(--spacing-small);
}
.sg-form-sections-card__option-group,
.sg-form-sections-card__field-group {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
margin-top: var(--spacing-large);
}
.sg-form-sections-card__field-group {
gap: var(--spacing-large);
}
.sg-form-sections-card .sg-labeled-input-row .sg-label {
min-width: var(--layout-form-sections-label-column-width);
flex: 0 0 var(--layout-form-sections-label-column-width);
margin-right: var(--spacing-large);
}
.sg-form-sections-card__option-group,
.sg-form-sections-card__actions {
padding-left: var(--layout-form-sections-interaction-indent);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-form-sections-card__chapter > :not(.sg-form-sections-card__chapter-title) + :not(.sg-form-sections-card__chapter-title) {
margin-top: var(--spacing-large);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-form-sections-card__chapter > .sg-form-sections-card__chapter-title + * {
margin-top: var(--spacing-large);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-form-sections-card__chapter > .sg-slider-row + .sg-slider-row,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-form-sections-card__chapter > .sg-checkbox-field-option + .sg-checkbox-field-option,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-form-sections-card__chapter > .sg-radio-activatable-group + .sg-radio-activatable-group {
margin-top: var(--spacing-small);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-form-sections-card__chapter > .sg-pulldown-panel__row + .sg-pulldown-panel__row {
margin-top: var(--spacing-large);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-pulldown-panel {
--sg-multiselect-label-column-width: var(--layout-multiselect-pulldown-label-column-width-fallback);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] > .sg-label,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-label,
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-pulldown-panel__label {
white-space: nowrap;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] {
display: grid;
grid-template-columns: max-content var(--sg-multiselect-label-column-width) minmax(0, 1fr) auto;
align-items: center;
column-gap: var(--spacing-large);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"].sg-slider-row--inactive-selectable {
opacity: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"].sg-slider-row--inactive-selectable .sg-slider {
opacity: var(--disabled-opacity);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"].sg-slider-row--inactive-selectable .sg-label,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"].sg-slider-row--inactive-selectable .sg-slider-value,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group[data-component-state="inactive-selectable"] > .sg-label,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group[data-component-state="inactive-selectable"] > .sg-radio-activatable-group__choices {
opacity: var(--disabled-opacity);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-mode-toggle {
grid-column: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-label {
grid-column: 2;
min-width: 0;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-slider {
grid-column: 3;
min-width: 0;
width: 100%;
max-width: none;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-slider-value {
grid-column: 4;
margin: 0;
min-width: 0;
line-height: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] {
-webkit-tap-highlight-color: transparent;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group {
display: grid;
grid-template-columns: max-content var(--sg-multiselect-label-column-width) minmax(0, 1fr);
align-items: center;
column-gap: var(--spacing-large);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-label {
grid-column: 2;
margin: 0;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-mode-toggle {
grid-column: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-radio-activatable-group__choices {
grid-column: 3;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group[data-component-state="inactive-selectable"] > .sg-radio-activatable-group__choices {
pointer-events: none;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"].sg-slider-row--inactive-selectable > :not(.sg-mode-toggle),
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group[data-component-state="inactive-selectable"] > :not(.sg-mode-toggle),
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row].sg-pulldown-panel__row--disabled > :not(.sg-mode-toggle) {
pointer-events: none;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] {
grid-template-columns: max-content var(--sg-multiselect-label-column-width) minmax(0, 1fr);
column-gap: var(--spacing-large);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-mode-toggle {
grid-column: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-pulldown-panel__label {
grid-column: 2;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-pulldown {
grid-column: 3;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row].sg-pulldown-panel__row--disabled {
opacity: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row].sg-pulldown-panel__row--disabled > .sg-pulldown-panel__label,
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row].sg-pulldown-panel__row--disabled > .sg-pulldown {
opacity: var(--disabled-opacity);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-pulldown-demo .sg-pulldown-panel {
min-width: 100%;
width: max-content;
max-width: calc(100vw - (2 * var(--spacing-large)));
}
@media (max-width: 48rem) {
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-pulldown-panel {
min-width: 100%;
width: max-content;
max-width: calc(100vw - (2 * var(--spacing-large)));
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] {
grid-template-columns: max-content minmax(0, 1fr) auto;
row-gap: var(--spacing-small);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] > .sg-label,
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-label,
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-pulldown-panel__label {
white-space: normal;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-mode-toggle {
grid-column: 1;
grid-row: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-label {
grid-column: 2;
grid-row: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-slider {
grid-column: 1 / 3;
grid-row: 2;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-slider-row[data-activatable="true"] .sg-slider-value {
grid-column: 3;
grid-row: 2;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group {
grid-template-columns: max-content minmax(0, 1fr);
row-gap: var(--spacing-small);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-label {
grid-column: 2;
grid-row: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-mode-toggle {
grid-column: 1;
grid-row: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] .sg-radio-activatable-group > .sg-radio-activatable-group__choices {
grid-column: 1 / -1;
grid-row: 2;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] {
grid-template-columns: max-content minmax(0, 1fr);
row-gap: var(--spacing-small);
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-mode-toggle {
grid-column: 1;
grid-row: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-pulldown-panel__label {
grid-column: 2;
grid-row: 1;
}
.sg-options-row[data-pattern="multiselektions-pulldown"] [data-pulldown-filter-row] > .sg-pulldown {
grid-column: 1 / -1;
grid-row: 2;
}
}
.sg-form-sections-card__actions {
display: flex;
width: 100%;
justify-content: flex-end;
gap: var(--spacing-small);
margin-top: 0;
padding-left: 0;
padding-right: 0;
}
.sg-form-sections-card__action {
width: auto;
}
.sg-navigation-card-layout {
width: 100%;
margin-top: var(--spacing-large);
}
.sg-navigation-card-block {
--surface-card: var(--surface-navigation-card);
--surface-card-body: var(--surface-navigation-card-body);
display: block;
flex: none;
min-width: 0;
max-width: none;
width: 100%;
}
.sg-navigation-card-center {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.sg-content-cards-group {
display: flex;
flex-direction: column;
gap: var(--layout-content-cards-group-gap);
}
@media (max-width: 48rem) {
.sg-form-sections-card .sg-labeled-input-row .sg-label {
min-width: 0;
flex: 0 0 auto;
margin-right: 0;
}
.sg-form-sections-card__option-group {
padding-left: 0;
}
}
+16
View File
@@ -0,0 +1,16 @@
/* ========================================================= */
/* Patterns: VSF List Card */
/* ========================================================= */
#layout-vsf-list-card .sg-vsf-list-card-limit-note {
margin: 0 0 var(--space-16) 0;
color: var(--text-vsf-list-card-limit-note);
}
#layout-vsf-list-card .sg-vsf-list-card__summary {
margin: var(--layout-vsf-list-card-summary-offset-block-start) 0 0 0;
}
.sg-vsf-list-card-context[data-pattern="overlay-card"] {
--layout-delete-confirmation-target-max-width: var(--layout-vsf-list-card-delete-confirmation-target-max-width);
}
+189
View File
@@ -0,0 +1,189 @@
/* ========================================================= */
/* Patterns: Overlay Card */
/* ========================================================= */
.sg-delete-confirmation-pattern {
width: 100%;
max-width: var(--layout-delete-confirmation-target-max-width);
}
.sg-delete-confirmation-pattern__stage {
position: relative;
overflow: visible;
}
.sg-delete-confirmation-pattern__host {
display: flex;
flex-direction: column;
}
.sg-delete-confirmation-pattern__host > .sg-delete-confirmation-pattern__target {
flex: 1 1 auto;
}
.sg-delete-confirmation-pattern__target {
position: relative;
overflow: visible;
}
.sg-delete-confirmation-pattern__target::after {
content: "";
position: absolute;
inset: 0;
background: var(--surface-delete-confirmation-target-dim-overlay);
opacity: 0;
pointer-events: none;
}
.sg-delete-confirmation-pattern__stage[data-dialog-open="true"] .sg-delete-confirmation-pattern__target::after {
opacity: var(--layout-delete-confirmation-target-dim-opacity);
pointer-events: auto;
}
.sg-delete-confirmation-pattern__floating-card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% * var(--layout-delete-confirmation-overlay-width-factor));
box-sizing: border-box;
max-width: calc(100% * var(--layout-delete-confirmation-overlay-width-factor));
height: var(--layout-delete-confirmation-overlay-height, auto);
overflow: hidden;
z-index: var(--layer-delete-confirmation-overlay);
box-shadow: var(--shadow-overlay);
}
.sg-delete-confirmation-pattern__floating-card.sg-card.sg-card--overlay-host {
overflow: hidden;
}
.sg-delete-confirmation-pattern__floating-card[hidden] {
display: none;
}
.sg-delete-confirmation-pattern__body {
display: flex;
flex-direction: column;
gap: var(--layout-delete-confirmation-content-gap);
background: var(--surface-delete-confirmation-overlay);
}
.sg-delete-confirmation-pattern__scroll-region {
display: flex;
flex: 1 1 auto;
min-height: 0;
flex-direction: column;
overflow: auto;
}
.sg-delete-confirmation-pattern__actions-segment {
border-bottom-left-radius: var(--radius-card);
border-bottom-right-radius: var(--radius-card);
flex: 0 0 auto;
}
.sg-delete-confirmation-pattern__list {
display: grid;
gap: var(--spacing-small);
margin: 0;
margin-top: var(--spacing-large);
padding: 0;
list-style: none;
}
.sg-delete-confirmation-pattern__list-item {
margin: 0;
}
.sg-delete-confirmation-pattern__list-button {
display: inline-flex;
width: 100%;
justify-content: flex-start;
gap: var(--spacing-small);
font-weight: var(--font-weight-regular);
color: var(--text-delete-confirmation-overlay);
background: var(--surface-control-inactive);
}
.sg-delete-confirmation-pattern__list-button[data-selected="true"] {
background: var(--surface-control-active);
}
.sg-delete-confirmation-pattern__list-button[data-selected="false"] {
background: var(--surface-control-inactive);
}
.sg-delete-confirmation-pattern__list-icon {
display: block;
flex: 0 0 auto;
width: 1rem;
height: 1rem;
background: center / contain no-repeat;
}
.sg-delete-confirmation-pattern__list-button[data-selected="true"] .sg-delete-confirmation-pattern__list-icon {
background-image: url("../assets/icons/star-filled.svg");
}
.sg-delete-confirmation-pattern__list-button[data-selected="false"] .sg-delete-confirmation-pattern__list-icon {
background-image: url("../assets/icons/star-outline.svg");
}
.sg-delete-confirmation-pattern__create-list-form {
margin-top: 0;
}
.sg-delete-confirmation-pattern__create-list-segment {
gap: 0;
}
.sg-delete-confirmation-pattern__create-list-title {
margin: 0 0 var(--spacing-large) 0;
}
.sg-delete-confirmation-pattern__create-list-form[hidden] {
display: none;
}
.sg-delete-confirmation-pattern__create-list-segment[hidden] {
display: none;
}
.sg-delete-confirmation-pattern__text {
margin: 0;
color: var(--text-delete-confirmation-overlay);
}
.sg-delete-confirmation-pattern__code {
font-weight: var(--font-weight-semibold);
}
.sg-delete-confirmation-pattern__input-row {
margin: var(--spacing-large) 0 0 0;
}
.sg-delete-confirmation-pattern__actions {
display: flex;
justify-content: flex-end;
gap: var(--layout-delete-confirmation-actions-gap);
margin-top: var(--layout-delete-confirmation-actions-offset-block-start);
}
.sg-delete-confirmation-pattern__actions--footer {
margin-top: 0;
}
.sg-delete-confirmation-pattern__scroll-region > .sg-delete-confirmation-pattern__create-list-segment {
flex: 0 0 auto;
}
.sg-delete-confirmation-pattern__create-list-toggle {
width: 100%;
}
@media (max-width: 48rem) {
.sg-delete-confirmation-pattern__actions {
flex-wrap: wrap;
}
}
+94
View File
@@ -0,0 +1,94 @@
/* ========================================================= */
/* Patterns: Notifications */
/* ========================================================= */
.sg-notifications-pattern {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-small);
align-items: flex-start;
width: 100%;
}
.sg-notifications-pattern__card {
flex: 0 0 100%;
width: 100%;
min-width: 0;
max-width: none;
}
/* Dokumentierte Pattern-Variante: Notifications innerhalb Group Card */
.sg-notifications-pattern.sg-group-card > .sg-notifications-pattern__card {
flex: 0 0 100%;
width: 100%;
min-width: 0;
max-width: none;
}
.sg-notifications-pattern.sg-notifications-pattern--multi-row .sg-notifications-pattern__card {
flex: 0 0 100%;
width: 100%;
}
.sg-notifications-pattern__card > .sg-notifications-pattern__text-segment {
height: auto;
}
.sg-notifications-pattern__card > .sg-notifications-pattern__title-segment {
height: auto;
}
.sg-notifications-pattern__card > .sg-notifications-pattern__text-segment.sg-notifications-pattern__text-segment--small {
height: auto;
}
.sg-vsf-meldungen-layout {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--spacing-small);
align-items: start;
width: 100%;
}
.sg-vsf-meldungen-layout > .sg-group-card {
min-width: 0;
}
.sg-vsf-meldungen-mobile {
display: none;
}
.sg-vsf-meldungen-mobile__panels {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
width: 100%;
}
.sg-vsf-meldungen-mobile__panel {
width: 100%;
}
@media (max-width: 767px) {
.sg-vsf-meldungen-layout {
display: none;
}
.sg-vsf-meldungen-mobile {
display: flex;
width: 100%;
}
.sg-notifications-pattern__card {
width: 100%;
min-width: 0;
max-width: none;
flex: 1 1 auto;
}
.sg-notifications-pattern__card > .sg-notifications-pattern__text-segment,
.sg-notifications-pattern__card > .sg-notifications-pattern__title-segment,
.sg-notifications-pattern__card > .sg-notifications-pattern__text-segment.sg-notifications-pattern__text-segment--small {
height: auto;
}
}
+87
View File
@@ -0,0 +1,87 @@
/* ========================================================= */
/* Patterns: Left Navigation */
/* ========================================================= */
.sg-left-navigation-pattern {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
}
.sg-left-navigation-pattern__layout {
display: flex;
align-items: flex-start;
gap: 0;
width: 100%;
min-width: 0;
}
.sg-left-navigation-pattern__header-row {
display: none;
}
.sg-left-navigation-pattern__toggle {
display: none;
}
.sg-left-navigation-pattern__menu--collapsed {
display: none;
}
.sg-left-navigation-pattern__group-card {
min-width: 0;
}
.sg-left-navigation-pattern__group-card--navigation {
flex: 0 0 15vw;
width: 15vw;
max-width: 15vw;
padding: var(--spacing-small);
margin: 0 var(--spacing-small) var(--spacing-small) 0;
}
.sg-left-navigation-pattern__group-card--content {
flex: 1 1 auto;
}
.sg-left-navigation-pattern__group-card--content .sg-group-card__heading {
flex: 0 1 auto;
width: auto;
margin-left: 0;
}
@media (min-width: 768px) {
.sg-left-navigation-pattern__group-card--navigation .sg-tab-button-group[data-component-variant="linksmenu-items"] {
justify-content: flex-start;
}
}
@media (max-width: 767px) {
.sg-left-navigation-pattern__layout {
flex-direction: column;
}
.sg-left-navigation-pattern__header-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-small);
margin-bottom: 0;
}
.sg-left-navigation-pattern__toggle {
display: inline-flex;
flex: 0 0 auto;
}
.sg-left-navigation-pattern__group-card--navigation {
flex: 0 0 auto;
width: 100%;
max-width: none;
margin: 0;
}
.sg-left-navigation-pattern__group-card--content {
margin-top: var(--spacing-small);
}
}
+172
View File
@@ -0,0 +1,172 @@
/* ========================================================= */
/* Layouts: Card Listen Seite */
/* ========================================================= */
.sg-card-list-page {
display: flex;
flex-direction: column;
}
.sg-card-list-page-drawer {
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: var(--layout-card-list-drawer-width);
max-width: 100%;
display: flex;
flex-direction: column;
transform: translateX(100%);
transition: transform 220ms ease;
background: var(--surface-card-list-drawer);
color: var(--text-card-list-drawer);
box-shadow: var(--shadow-overlay);
z-index: 1000;
overflow-y: auto;
}
.sg-card-list-page-drawer[data-open="true"] {
transform: translateX(0);
}
.sg-card-list-page-drawer__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-small);
padding:
var(--card-segment-padding-vertical)
var(--layout-page-content-inset-inline);
}
.sg-card-list-page-drawer__title {
margin: 0;
color: inherit;
}
.sg-card-list-page-drawer__content {
display: flex;
flex-direction: column;
gap: var(--spacing-large);
padding:
var(--card-segment-padding-vertical)
var(--layout-page-content-inset-inline)
var(--card-segment-padding-vertical)
var(--layout-page-content-inset-inline);
}
.sg-card-list-page > * + * {
margin-top: var(--spacing-large);
}
.sg-card-list-page > .sg-options-row {
margin-top: var(--layout-options-row-margin-top);
}
.sg-card-list-page__intro-block {
margin-top: var(--spacing-large);
margin-bottom: var(--spacing-large);
}
.sg-card-list-page__intro-block .sg-text-layout-pattern__sample--sixty-width {
width: min(60vw, 100%);
}
@media (max-width: 767px) {
.sg-card-list-page-drawer {
display: none;
}
.sg-card-list-page__intro-block .sg-text-layout-pattern__sample--sixty-width {
width: 100%;
}
}
.sg-card-list-page__object-grid,
.sg-card-list-page__navigation {
width: 100%;
}
.sg-vsf-drawer-card {
--surface-card-header-primary: var(--surface-vsf-drawer-object-card-header);
--surface-card: var(--surface-vsf-drawer-object-card-body);
--surface-card-body: var(--surface-vsf-drawer-object-card-body);
--text-card-header: var(--text-vsf-drawer-object-card-heading);
--text-card-body: var(--text-vsf-drawer-object-card-body);
width: 100%;
min-width: 0;
max-width: none;
align-self: stretch;
height: auto;
}
.sg-vsf-drawer-card__content {
color: var(--text-vsf-drawer-object-card-body);
}
.sg-vsf-drawer-card .sg-text-layout-pattern__two-column,
.sg-vsf-drawer-card .sg-text-layout-pattern__column {
color: var(--text-vsf-drawer-object-card-body);
}
.sg-vsf-drawer-card .sg-text-layout-pattern__two-column {
gap: var(--layout-vsf-drawer-object-card-column-gap);
}
.sg-vsf-drawer-card__actions-segment {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: var(--spacing-large);
background: var(--surface-vsf-drawer-object-card-body);
}
.sg-vsf-drawer-card__actions-segment .sg-interaction-element.sg-button {
height: auto;
width: 100%;
}
#vsf-business-model-toggle.sg-interaction-element.sg-button {
background: var(--surface-portal-header-tab);
color: var(--text-portal-header-tab);
}
.sg-inline-controls-card {
--surface-card-body: var(--surface-card-segment-neutral);
}
.sg-card-segment.sg-inline-header-row {
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: var(--spacing-small);
}
.sg-card-segment.sg-inline-controls-row {
flex-direction: row;
align-items: center;
justify-content: flex-end;
gap: var(--spacing-small);
flex-wrap: nowrap;
}
.sg-vsf-drawer-object-card__heading {
color: var(--text-vsf-drawer-object-card-heading);
margin: 0;
}
.sg-analysis-intro-block {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
}
.sg-analysis-intro-block .sg-heading-h2 {
margin: 0;
}
.sg-analysis-intro-block .sg-text-layout-pattern__sample {
margin: 0;
color: var(--text-vsf-drawer-object-card-body);
}
+79
View File
@@ -0,0 +1,79 @@
/* ========================================================= */
/* Patterns: Text Layouts */
/* ========================================================= */
.sg-text-layout-pattern {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
}
.sg-text-layout-pattern__preview-surface {
width: 100%;
box-sizing: border-box;
padding: var(--spacing-large);
border-radius: var(--radius-card);
background: var(--surface-text-layout-preview);
}
.sg-text-layout-pattern__sample {
margin: 0;
}
.sg-text-layout-pattern__sample--full-width {
width: 100%;
}
.sg-text-layout-pattern__sample--sixty-width {
width: 60%;
}
.sg-text-layout-pattern__sample--two-column {
margin: 0;
}
.sg-text-layout-pattern__two-column {
width: 100%;
min-width: 0;
display: grid;
grid-template-columns: var(--layout-text-layout-two-column-columns);
column-gap: var(--layout-text-layout-column-gap);
}
.sg-text-layout-pattern__three-column-distributed {
width: 100%;
min-width: 0;
display: grid;
grid-template-columns: var(--layout-text-layout-three-column-columns);
column-gap: var(--layout-text-layout-column-gap);
}
.sg-text-layout-pattern__column {
margin: 0;
min-width: 0;
}
.sg-text-layout-pattern__three-column-distributed > .sg-body {
margin: 0;
}
.sg-text-layout-pattern__column--align-left {
text-align: var(--text-align-text-layout-column-left);
}
.sg-text-layout-pattern__column--align-center {
text-align: var(--text-align-text-layout-column-center);
}
.sg-text-layout-pattern__column--align-right {
text-align: var(--text-align-text-layout-column-right);
}
@media (max-width: 767px) {
.sg-text-layout-pattern__sample--sixty-width,
.sg-text-layout-pattern__sample--two-column,
.sg-text-layout-pattern__two-column,
.sg-text-layout-pattern__three-column-distributed {
width: 100%;
}
}
@@ -0,0 +1,47 @@
/* ========================================================= */
/* Patterns: Card Gruppe mit Tastennavigation */
/* ========================================================= */
.sg-content-block-card-group {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
width: 100%;
}
.sg-content-block-card-group[hidden] {
display: none;
}
.sg-content-block-card-group__tabs,
.sg-content-block-card-group__panels,
.sg-content-block-card-group__panel,
.sg-content-block-card-group__card {
width: 100%;
}
.sg-content-block-card-group__panel[hidden] {
display: none;
}
.sg-content-block-card-group__title {
color: var(--text-content-block-card-title);
background: var(--surface-content-block-card-title);
}
.sg-content-block-card-group__content {
color: var(--text-content-block-card-content);
background: var(--surface-content-block-card-content);
}
.sg-content-block-card-group__content .sg-body {
margin: 0;
}
@media (max-width: 767px) {
.sg-content-block-card-group__tabs[role="tablist"] > [role="tab"] {
flex: 1 1 auto;
min-width: max-content;
white-space: nowrap;
}
}
@@ -0,0 +1,96 @@
/* ========================================================= */
/* Layouts: VSF List Detailseite */
/* ========================================================= */
.sg-vsf-list-detail-page {
display: flex;
flex-direction: column;
}
.sg-vsf-list-detail-page > * + * {
margin-top: var(--spacing-large);
}
.sg-vsf-list-detail-page__content {
display: flex;
gap: var(--spacing-small);
width: 100%;
}
.sg-vsf-list-detail-page__mobile-tabs {
display: none;
}
.sg-vsf-list-detail-page__left-column {
width: 30%;
min-width: 30%;
}
.sg-vsf-list-detail-page__right-column {
width: 70%;
min-width: 0;
}
.sg-vsf-list-detail-page__left-column .sg-group-card {
display: flex;
flex-direction: column;
width: 100%;
}
.sg-vsf-list-detail-page__left-column .sg-group-card > .sg-card {
flex: 0 0 100%;
width: 100%;
}
.sg-vsf-list-detail-page__notification-card.sg-vsf-list-detail-page__notification-card--hidden {
display: none;
}
.sg-vsf-list-detail-page__meldungen-overlay-pattern {
max-width: 100%;
}
.sg-vsf-list-detail-page__meldungen-overlay-pattern .sg-delete-confirmation-pattern__floating-card {
top: calc(var(--spacing-large) * 5);
transform: translateX(-50%);
}
.sg-vsf-list-detail-page__mobile-toggle {
display: none;
}
@media (max-width: 767px) {
.sg-vsf-list-detail-page__mobile-tabs {
display: flex;
width: 100%;
margin-bottom: 0;
}
.sg-vsf-list-detail-page__content {
display: block;
margin-top: var(--spacing-small);
}
.sg-vsf-list-detail-page__left-column {
width: 100%;
min-width: 0;
}
.sg-vsf-list-detail-page__right-column {
width: 100%;
}
.sg-vsf-list-detail-page__content > [data-vsf-list-detail-panel] {
width: 100%;
}
.sg-vsf-list-detail-page__content > [data-vsf-list-detail-panel][hidden] {
display: none;
}
.sg-vsf-list-detail-page__mobile-toggle {
display: inline-flex;
width: 100%;
margin-bottom: var(--spacing-large);
}
}
@@ -0,0 +1,55 @@
/* ========================================================= */
/* Layouts: VSF Listen Übersicht Seite V2 */
/* ========================================================= */
.sg-vsf-list-overview-page-v2 {
display: flex;
flex-direction: column;
}
.sg-vsf-list-overview-page-v2 > * + * {
margin-top: var(--spacing-large);
}
.sg-vsf-list-overview-page-v2 .sg-portal-header-pattern-variant {
margin-bottom: 0;
}
.sg-vsf-list-overview-page-v2 > .sg-vsf-list-overview-page-v2__intro {
margin-top: var(--spacing-large);
}
.sg-vsf-list-overview-page-v2__content {
display: flex;
gap: var(--spacing-small);
width: 100%;
}
.sg-vsf-list-overview-page-v2__primary {
width: 70%;
min-width: 0;
}
.sg-vsf-list-overview-page-v2__secondary {
width: 30%;
min-width: 0;
}
.sg-vsf-list-overview-page-v2__intro .sg-text-layout-pattern__sample--sixty-width {
color: var(--color-font-light);
}
@media (max-width: 767px) {
.sg-vsf-list-overview-page-v2__content {
display: block;
}
.sg-vsf-list-overview-page-v2__primary,
.sg-vsf-list-overview-page-v2__secondary {
width: 100%;
}
.sg-vsf-list-overview-page-v2__secondary {
margin-top: var(--spacing-large);
}
}
+29
View File
@@ -0,0 +1,29 @@
/* ========================================================= */
/* Layouts: VSF Register Step 1 */
/* ========================================================= */
.sg-vsf-register-step-1 {
display: block;
margin-top: clamp(32px, 6vw, 100px);
padding: 0 var(--layout-page-content-inset-inline);
box-sizing: border-box;
}
.sg-vsf-register-step-1-page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.sg-vsf-register-step-1__card {
width: 100%;
max-width: var(--layout-object-card-max-width);
margin: 0 auto;
}
.sg-vsf-register-step-1__social-links {
display: flex;
justify-content: center;
gap: var(--spacing-large);
margin-top: var(--spacing-large);
}
+8
View File
@@ -0,0 +1,8 @@
/* ========================================================= */
/* Layouts: Page Layout App */
/* ========================================================= */
.sg-page-layout-app__heading-block {
margin-top: var(--spacing-large);
margin-bottom: var(--spacing-large);
}
+33
View File
@@ -0,0 +1,33 @@
/* ========================================================= */
/* Layouts: Page Layout Public */
/* ========================================================= */
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
main {
flex: 1;
display: flex;
flex-direction: column;
}
.sg-page-layout-public__heading-block {
margin-top: calc(var(--spacing-large) * 2);
margin-bottom: var(--spacing-large);
}
.sg-page-layout-public__content-mirror {
width: min(calc(100% - (var(--spacing-large) * 2)), 1100px);
max-width: 1100px;
margin-inline: auto;
display: flex;
flex-direction: column;
flex: 1;
}
.sg-page-layout-public__footer-card {
margin-top: auto;
}
+253
View File
@@ -0,0 +1,253 @@
/* ========================================================= */
/* Components: Cards */
/* ========================================================= */
.sg-card {
--layout-card-segment-padding-top: var(--card-segment-padding-vertical);
--layout-card-segment-padding-right: var(--card-segment-padding-horizontal);
--layout-card-segment-padding-bottom: var(--card-segment-padding-vertical);
--layout-card-segment-padding-left: var(--card-segment-padding-horizontal);
--layout-card-body-padding-top: var(--layout-card-segment-padding-top);
--layout-card-body-padding-right: var(--layout-card-segment-padding-right);
--layout-card-body-padding-bottom: var(--layout-card-segment-padding-bottom);
--layout-card-body-padding-left: var(--layout-card-segment-padding-left);
--layout-card-body-text-margin: 0;
display: flex;
flex-direction: column;
overflow: hidden;
width: 100%;
box-sizing: border-box;
border: var(--border-none);
border-radius: var(--radius-card);
box-shadow: var(--shadow-none);
background: var(--surface-card);
}
.sg-card.sg-card--content-card-dark {
--surface-card: var(--surface-card-group);
--surface-card-body: var(--surface-card-group);
--text-card-body: var(--text-card-header);
}
.sg-card.sg-card--content-card-dark .sg-card-segment--body {
color: var(--color-font-light);
}
.sg-card.sg-card--content-card-dark .sg-text-layout-pattern__column,
.sg-card.sg-card--content-card-dark .sg-body {
color: var(--color-font-light);
}
.sg-card.sg-card--overlay-host {
overflow: visible;
}
.sg-card > .sg-card-segment:first-child {
border-top-left-radius: var(--radius-card);
border-top-right-radius: var(--radius-card);
}
.sg-card > .sg-card-segment:last-child {
border-bottom-left-radius: var(--radius-card);
border-bottom-right-radius: var(--radius-card);
}
@media (max-width: 48rem) {
:root {
--card-segment-padding-horizontal: var(--card-segment-padding-horizontal-mobile);
}
}
.sg-card-segment {
display: flex;
flex-direction: column;
height: auto;
justify-content: flex-start;
align-items: stretch;
align-content: flex-start;
padding:
var(--layout-card-segment-padding-top)
var(--layout-card-segment-padding-right)
var(--layout-card-segment-padding-bottom)
var(--layout-card-segment-padding-left);
gap: var(--layout-card-segment-content-gap);
}
.sg-card-segment--header {
color: var(--text-card-header);
}
.sg-card-segment--body {
justify-content: var(--layout-card-body-content-justify);
padding:
var(--layout-card-body-padding-top)
var(--layout-card-body-padding-right)
var(--layout-card-body-padding-bottom)
var(--layout-card-body-padding-left);
color: var(--text-card-body);
background: var(--surface-card-body);
}
.sg-card-segment--body > .sg-body {
margin: var(--layout-card-body-text-margin, 0);
}
.sg-card-segment--body.sg-object-card__content > .sg-body.sg-company-card__summary {
margin: var(--layout-company-card-analysis-gap-after-moat) 0 0 0;
}
.sg-card-segment--darkblue {
background: var(--surface-card-header-primary);
}
.sg-card-segment--darkgreen {
background: var(--surface-card-header-alternative);
}
.sg-card-segment--darkbrown {
background: var(--surface-card-header-muted);
}
.sg-card-segment--signal-red {
background: var(--color-signal-red);
color: var(--text-card-header);
}
.sg-card-segment--signal-green {
background: var(--color-signal-green);
color: var(--text-card-header);
}
.sg-card-segment--signal-yellow {
background: var(--color-signal-yellow);
color: var(--text-card-header);
}
.sg-card-segment--gray {
background: var(--surface-card-segment-neutral);
}
.sg-card-segment--white {
background: var(--surface-object-card-lower-segment);
}
.sg-card.sg-card--notification-white {
--text-card-header: var(--text-card-body);
}
.sg-card--content-card {
--surface-card-header-primary: var(--surface-content-block-card-title);
--surface-card-body: var(--surface-content-block-card-content);
--text-card-header: var(--text-content-block-card-title);
--text-card-body: var(--text-content-block-card-content);
}
.sg-card-segment + .sg-card-segment {
box-shadow: inset 0 1px 0 var(--divider-card-segment);
}
.sg-card-segment--darkbrown + .sg-card-segment--body {
box-shadow: none;
}
.sg-card-segment.sg-object-card__header {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.sg-card-segment--body.sg-object-card__content {
background: var(--surface-object-card-lower-segment);
}
.sg-card-segment--body.sg-object-card__actions-segment {
background: var(--surface-object-card-lower-segment);
}
.sg-card-segment.sg-vsf-drawer-card__actions-segment {
flex-direction: column;
align-items: flex-start;
gap: var(--spacing-large);
}
.sg-group-card {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-small);
align-items: flex-start;
width: 100%;
box-sizing: border-box;
padding: var(--spacing-small);
border-radius: var(--radius-card);
background: var(--surface-card-group);
}
.sg-group-card > .sg-card {
flex: 1 1 calc(50% - var(--spacing-small));
width: calc(50% - var(--spacing-small));
}
.sg-group-card--margin-after-large {
margin-bottom: var(--spacing-large);
}
.sg-group-card__header-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-small);
width: 100%;
margin-bottom: var(--spacing-small);
}
.sg-group-card__heading {
flex: 0 0 100%;
margin-top: 0;
margin-right: 0;
margin-bottom: var(--spacing-small);
margin-left: var(--card-segment-padding-horizontal);
}
.sg-group-card__header-row .sg-group-card__heading {
flex: 1 1 auto;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: var(--card-segment-padding-horizontal);
}
.sg-group-card__header-row .sg-sandwich-menu-wrap {
margin-right: var(--card-segment-padding-horizontal);
}
.sg-page-cards .sg-preview-area {
display: flex;
flex-direction: column;
width: 100%;
}
.sg-page-cards .sg-preview-area > .sg-card,
.sg-page-cards .sg-preview-area > .sg-transparent-card {
width: 100%;
max-width: none;
}
.sg-page-cards .sg-group-card > .sg-card {
flex: 0 0 100%;
width: 100%;
}
.sg-transparent-card {
color: var(--text-card-transparent);
background: var(--surface-card-transparent);
padding:
0
var(--card-segment-padding-horizontal)
0
var(--card-segment-padding-horizontal);
}
.sg-transparent-card p {
margin: 0;
color: var(--text-card-transparent);
}
+297
View File
@@ -0,0 +1,297 @@
/* ========================================================= */
/* Components: Charts */
/* ========================================================= */
.sg-score-bar-list {
display: grid;
grid-template-columns: var(--layout-score-bar-item-columns);
column-gap: var(--layout-score-bar-item-gap);
row-gap: var(--spacing-small);
align-items: center;
width: 100%;
}
.sg-score-bar-item {
display: contents;
}
.sg-score-bar-list--single-score {
--layout-score-bar-item-columns: var(--layout-score-bar-item-single-score-columns);
}
.sg-score-state--positive,
.sg-score-state--warning,
.sg-score-state--neutral,
.sg-score-state--negative {
margin: 0;
justify-self: end;
text-align: right;
}
.sg-score-state--positive {
color: var(--text-score-state-positive);
}
.sg-score-state--warning {
color: var(--text-score-state-warning);
}
.sg-score-state--neutral {
color: var(--text-score-state-neutral);
}
.sg-score-state--negative {
color: var(--text-score-state-negative);
}
.sg-score-bar-label {
margin: 0;
color: var(--text-chart-default);
}
.sg-score-bar {
position: relative;
height: var(--score-bar-height);
overflow: visible;
border-radius: var(--radius-graph-bar);
background: var(--surface-score-bar-track);
}
.sg-score-bar--marker-mid {
--score-marker-position: 50%;
}
.sg-score-bar--no-value {
display: block;
}
.sg-score-bar__value {
height: 100%;
border-radius: var(--radius-graph-bar);
}
.sg-score-bar__value--w96 { width: 96%; }
.sg-score-bar__value--w64 { width: 64%; }
.sg-score-bar__value--w35 { width: 35%; }
.sg-score-bar__value--positive { background: var(--chart-value-positive); }
.sg-score-bar__value--neutral { background: var(--chart-value-neutral); }
.sg-score-bar__value--negative { background: var(--chart-value-negative); }
.sg-score-bar__median-marker {
position: absolute;
top: 50%;
left: var(--score-marker-position);
width: var(--score-marker-width);
height: var(--score-marker-height);
border-radius: 0;
background: var(--chart-marker-line);
transform: translate(-50%, -50%);
}
.sg-score-bar__median-marker--outline {
border: var(--chart-grid-line-width) solid var(--chart-marker-line);
background: transparent;
}
.sg-score-bar__empty-state {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: flex-start;
padding-inline-start: var(--spacing-small);
color: var(--text-chart-default);
font-family: var(--font-family-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
pointer-events: none;
}
.sg-chart-preview-area {
min-width: var(--layout-object-card-min-width);
max-width: var(--layout-object-card-max-width);
width: 100%;
}
.sg-bar-chart {
display: block;
width: 100%;
box-sizing: border-box;
padding: 0;
background: var(--surface-chart-area);
color: var(--text-chart-default);
}
.sg-chart-frame {
display: grid;
grid-template-columns: min-content 1fr;
column-gap: var(--chart-axis-label-gap);
height: calc(var(--chart-height-bar) * 0.7);
}
.sg-chart-y-labels {
position: relative;
width: min-content;
margin: 0;
padding: 0;
list-style: none;
color: var(--text-chart-default);
text-align: right;
pointer-events: none;
}
.sg-chart-y-labels li {
position: absolute;
white-space: nowrap;
right: 0;
top: var(--chart-label-position);
transform: translateY(-50%);
}
.sg-chart-x-labels {
display: grid;
grid-template-columns: repeat(10, 1fr);
margin: var(--spacing-small) 0 var(--spacing-large) 0;
padding: 0 0 0 calc(var(--interaction-height) + var(--chart-axis-label-gap));
list-style: none;
color: var(--text-chart-default);
text-align: center;
}
.sg-chart-x-labels--line {
position: relative;
display: block;
height: var(--spacing-large);
grid-template-columns: none;
}
.sg-chart-x-labels--line li {
position: absolute;
left: var(--chart-label-position);
transform: translateX(-50%);
}
.sg-chart-y-labels li,
.sg-chart-x-labels li {
font-family: var(--font-family-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
}
.sg-bar-chart__svg,
.sg-line-chart__svg {
display: block;
width: 100%;
height: 100%;
overflow: hidden;
}
.sg-bar-chart__grid-line,
.sg-line-chart__grid-line {
stroke: var(--chart-grid-line);
stroke-width: var(--chart-grid-line-width);
}
.sg-bar-chart__axis-line,
.sg-line-chart__axis-line {
stroke: var(--chart-axis-line);
stroke-width: var(--chart-grid-line-width);
}
.sg-bar-chart__bar {
rx: var(--radius-graph-bar);
ry: var(--radius-graph-bar);
}
.sg-bar-chart__bar--value { fill: var(--chart-value-primary); }
.sg-bar-chart__bar--median { fill: var(--chart-value-reference); }
.sg-bar-chart__label,
.sg-line-chart__label { display: none; }
.sg-bar-chart__legend,
.sg-line-chart__legend {
display: flex;
gap: var(--spacing-large);
padding-left: 0;
margin-left: 0;
}
.sg-bar-chart__legend {
flex-wrap: wrap;
margin-top: 0;
color: var(--text-chart-default);
}
.sg-line-chart__legend {
margin-top: var(--spacing-large);
}
.sg-bar-chart__legend-item,
.sg-line-chart__legend-item {
display: inline-flex;
align-items: center;
gap: var(--spacing-small);
color: var(--text-chart-default);
font-family: var(--font-family-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
}
.sg-bar-chart__legend-swatch {
display: inline-block;
width: var(--interaction-height);
height: var(--interaction-height);
border-radius: var(--radius-interaction);
}
.sg-bar-chart__legend-swatch--value { background: var(--chart-value-primary); }
.sg-bar-chart__legend-swatch--median { background: var(--chart-value-reference); }
.sg-line-chart {
width: 100%;
box-sizing: border-box;
padding: 0;
background: var(--surface-chart-area);
color: var(--text-chart-default);
}
.sg-chart-frame--line {
height: calc(var(--chart-height-line) * 0.7);
}
.sg-line-chart__line {
fill: none;
stroke: var(--chart-value-primary);
stroke-width: var(--chart-line-width);
stroke-linecap: round;
stroke-linejoin: round;
}
.sg-line-chart__median-line {
fill: none;
stroke: var(--chart-median-line);
stroke-width: var(--chart-grid-line-width);
stroke-dasharray: var(--sandwich-line-height) var(--sandwich-line-height);
}
.sg-line-chart__legend-line {
display: inline-block;
width: var(--spacing-large);
height: var(--chart-line-width);
background: var(--chart-value-primary);
}
.sg-line-chart__legend-line--median {
height: var(--chart-grid-line-width);
background: repeating-linear-gradient(
to right,
var(--chart-median-line) 0,
var(--chart-median-line) var(--sandwich-line-height),
transparent var(--sandwich-line-height),
transparent calc(var(--sandwich-line-height) * 2)
);
}
+176
View File
@@ -0,0 +1,176 @@
/* ========================================================= */
/* Components: Data Display */
/* ========================================================= */
.sg-data-table {
--data-table-column-count: 3;
width: 100%;
border-collapse: collapse;
background: var(--surface-data-table);
table-layout: fixed;
}
.sg-data-table th,
.sg-data-table td {
width: calc(100% / var(--data-table-column-count));
padding: 0 0 var(--spacing-small) 0;
border: var(--border-none);
text-align: left;
vertical-align: top;
}
.sg-data-table[data-component="data-columns"] {
--data-table-column-count: 2;
}
.sg-data-table th {
font-family: var(--font-family-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
color: var(--text-data-table-default);
background: var(--surface-data-table-header);
}
.sg-data-table td {
font-family: var(--font-family-base);
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-base);
color: var(--text-data-table-default);
background: var(--surface-data-table-cell);
}
.sg-data-table__label,
.sg-data-table__value {
font-weight: var(--font-weight-semibold);
}
.sg-data-table__value--warning {
color: var(--text-data-table-warning);
}
.sg-data-table__help-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--small-interaction-element-size);
height: var(--small-interaction-element-size);
border: var(--border-none);
border-radius: 50%;
box-shadow: var(--shadow-none);
font-family: var(--font-family-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-semibold);
line-height: 1;
color: var(--text-data-table-help-icon);
background: var(--surface-data-table-help-icon);
}
.sg-large-table {
width: 100%;
}
.sg-large-table__title-segment {
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: var(--spacing-large);
}
.sg-large-table__row {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
align-items: stretch;
gap: 0;
width: 100%;
box-sizing: border-box;
background: var(--color-white);
}
.sg-large-table__row--hidden {
display: none;
}
.sg-large-table__row--header {
font-weight: var(--font-weight-semibold);
background: var(--color-medium-grey);
}
.sg-large-table__row--striped-light {
background: var(--color-light-grey);
}
.sg-large-table__row--load-more {
background: var(--color-medium-grey);
}
.sg-large-table__cell {
min-width: 0;
padding: 0 var(--spacing-small);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.sg-large-table__cell--load-more {
grid-column: 1 / -1;
padding: 0;
white-space: normal;
}
.sg-large-table__load-more-layout {
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
.sg-large-table__cell--header {
padding: 0;
}
.sg-large-table__sort-button {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 0.2rem;
width: 100%;
padding: 0 var(--spacing-small);
border: var(--border-none);
background: var(--color-transparent);
color: inherit;
font: inherit;
font-weight: var(--font-weight-semibold);
text-align: left;
cursor: pointer;
}
.sg-large-table__sort-button:focus-visible {
outline: 2px solid var(--color-darkblue);
outline-offset: -2px;
}
.sg-large-table__sort-icon {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
width: 0.85rem;
height: 0.85rem;
line-height: 1;
transform: translateY(0.02em);
}
.sg-large-table__sort-icon::before {
content: "";
display: block;
width: 0;
height: 0;
border-left: 0.36rem solid transparent;
border-right: 0.36rem solid transparent;
border-bottom: 0.55rem solid currentColor;
}
.sg-large-table__sort-icon[data-direction="descending"]::before {
transform: rotate(180deg);
}
+17
View File
@@ -0,0 +1,17 @@
/* ========================================================= */
/* Components: Typography */
/* ========================================================= */
.sg-typography-preview {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
color: var(--text-typography-preview);
}
.sg-typography-preview h1,
.sg-typography-preview h2,
.sg-typography-preview p {
color: var(--text-typography-preview);
margin-top: 0;
}