profile-pane 3.1.3 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/lib/FriendList.d.ts +0 -1
  2. package/lib/FriendList.d.ts.map +1 -1
  3. package/lib/FriendList.js +5 -33
  4. package/lib/SocialPresenter.js +1 -1
  5. package/lib/addMeToYourFriends.d.ts +4 -3
  6. package/lib/addMeToYourFriends.d.ts.map +1 -1
  7. package/lib/addMeToYourFriends.js +25 -9
  8. package/lib/editProfilePane/EditCVCard.d.ts.map +1 -1
  9. package/lib/editProfilePane/EditCVCard.js +2 -7
  10. package/lib/editProfilePane/EditCommunitiesCard.d.ts +3 -1
  11. package/lib/editProfilePane/EditCommunitiesCard.d.ts.map +1 -1
  12. package/lib/editProfilePane/EditCommunitiesCard.js +58 -23
  13. package/lib/editProfilePane/EditFriendsCard.d.ts +3 -1
  14. package/lib/editProfilePane/EditFriendsCard.d.ts.map +1 -1
  15. package/lib/editProfilePane/EditFriendsCard.js +58 -23
  16. package/lib/editProfilePane/EditOtherPreferences.js +1 -1
  17. package/lib/editProfilePane/EditProfileView.d.ts +1 -1
  18. package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
  19. package/lib/editProfilePane/EditProfileView.js +7 -3
  20. package/lib/editProfilePane/EditSocialCard.d.ts.map +1 -1
  21. package/lib/editProfilePane/EditSocialCard.js +2 -7
  22. package/lib/editProfilePane/editProfilePresenter.d.ts +4 -0
  23. package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -0
  24. package/lib/editProfilePane/editProfilePresenter.js +108 -0
  25. package/lib/profile-pane.js +1005 -340
  26. package/lib/profile-pane.js.map +1 -1
  27. package/lib/profile-pane.min.js +45 -46
  28. package/lib/profile-pane.min.js.map +1 -1
  29. package/lib/rdfFormsHelper.d.ts +1 -0
  30. package/lib/rdfFormsHelper.d.ts.map +1 -1
  31. package/lib/rdfFormsHelper.js +125 -0
  32. package/lib/styles/ProfileCard.css +6 -0
  33. package/lib/styles/ProfileView.css +3 -5
  34. package/lib/styles/editProfile.css +62 -0
  35. package/lib/styles/profileRDFFormsEnforced.css +427 -0
  36. package/lib/styles/utilities.css +30 -1
  37. package/lib/texts.d.ts +5 -5
  38. package/lib/texts.d.ts.map +1 -1
  39. package/lib/texts.js +5 -5
  40. package/package.json +9 -6
  41. package/lib/styles/rdfFormsEnforced.css +0 -186
@@ -4,4 +4,5 @@ formSource: string, // The imported form Turtle source
4
4
  formName: string, // The name of the form file (e.g., 'socialMedia.ttl')
5
5
  store: Store, dom: Document, editableProfile: NamedNode | null, whichForm?: string): void;
6
6
  export declare function loadDocument(store: Store, documentSource: string, documentName: string, documentURI?: string): void;
7
+ export declare function skipLabelsFromTabbing(root: HTMLElement): void;
7
8
  //# sourceMappingURL=rdfFormsHelper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rdfFormsHelper.d.ts","sourceRoot":"","sources":["../src/rdfFormsHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAyB,MAAM,QAAQ,CAAA;AAKhE,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,SAAS,EAAE,yCAAyC;AAC7D,UAAU,EAAE,MAAM,EAAE,kCAAkC;AACtD,QAAQ,EAAE,MAAM,EAAI,sDAAsD;AAC1E,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,QAAQ,EACb,eAAe,EAAE,SAAS,GAAG,IAAI,EACjC,SAAS,CAAC,EAAE,MAAM,QAmBjB;AAGH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,WAAW,CAAC,EAAE,MAAM,QAUrB"}
1
+ {"version":3,"file":"rdfFormsHelper.d.ts","sourceRoot":"","sources":["../src/rdfFormsHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAyB,MAAM,QAAQ,CAAA;AAKhE,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,SAAS,EAAE,yCAAyC;AAC7D,UAAU,EAAE,MAAM,EAAE,kCAAkC;AACtD,QAAQ,EAAE,MAAM,EAAI,sDAAsD;AAC1E,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,QAAQ,EACb,eAAe,EAAE,SAAS,GAAG,IAAI,EACjC,SAAS,CAAC,EAAE,MAAM,QAqFjB;AA0DH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,WAAW,CAAC,EAAE,MAAM,QAUrB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CA2B7D"}
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = renderForm;
7
7
  exports.loadDocument = loadDocument;
8
+ exports.skipLabelsFromTabbing = skipLabelsFromTabbing;
8
9
  var _rdflib = require("rdflib");
9
10
  var _solidUi = require("solid-ui");
10
11
  const baseUri = 'https://solidos.github.io/profile-pane/src/ontology/';
@@ -25,8 +26,112 @@ store, dom, editableProfile, whichForm) {
25
26
  _solidUi.widgets.appendForm(dom, div, {}, subject, formThis, editableProfile, (ok, mes) => {
26
27
  if (!ok) _solidUi.widgets.errorMessageBlock(dom, mes);
27
28
  });
29
+
30
+ // Ensure that when a user clicks “Add skill” or “Add language”, the newly
31
+ // created input receives focus. Solid-UI provides only a generic "Add" button.
32
+ // We detect the "add" control by the plus icon it uses and focus the last
33
+ // text input in the surrounding multiple-field container.
34
+ enableFocusOnAdd(div);
35
+
36
+ // Track the last click/tap position so popups (like solid-ui delete confirmations)
37
+ // can be positioned closer to where the user clicked.
38
+ let lastClick = {
39
+ x: 0,
40
+ y: 0
41
+ };
42
+ div.addEventListener('pointerdown', event => {
43
+ lastClick = {
44
+ x: event.clientX,
45
+ y: event.clientY
46
+ };
47
+ }, {
48
+ capture: true
49
+ });
50
+
51
+ // Solid-UI injects a popup DIV (position:absolute, top:-1em) under a relative container.
52
+ // Detect it and reposition it using last click coordinates.
53
+ const repositionPopup = popup => {
54
+ const win = dom.defaultView || window;
55
+ const padding = 10;
56
+ const maxWidth = win.innerWidth - padding;
57
+ const maxHeight = win.innerHeight - padding;
58
+
59
+ // Force fixed positioning, then clamp to viewport so it doesn't get cut off.
60
+ popup.style.position = 'fixed';
61
+ popup.style.zIndex = '9999';
62
+ popup.style.pointerEvents = 'auto';
63
+ popup.style.opacity = '1';
64
+ popup.style.visibility = 'visible';
65
+
66
+ // Use getBoundingClientRect after it is in DOM; if it is 0x0, fall back to default offset.
67
+ const rect = popup.getBoundingClientRect();
68
+ const popupWidth = rect.width || 200;
69
+ const popupHeight = rect.height || 100;
70
+ const left = Math.min(Math.max(lastClick.x + padding, padding), maxWidth - popupWidth);
71
+ const top = Math.min(Math.max(lastClick.y + padding, padding), maxHeight - popupHeight);
72
+ popup.style.left = `${left}px`;
73
+ popup.style.top = `${top}px`;
74
+ };
75
+ const observer = new MutationObserver(mutations => {
76
+ for (const mutation of mutations) {
77
+ for (const node of Array.from(mutation.addedNodes)) {
78
+ if (!(node instanceof HTMLElement)) continue;
79
+ // Solid-UI popups are divs with inline position:absolute and grid display
80
+ if (node.style.position === 'absolute' && node.style.display === 'grid' && node.style.top === '-1em') {
81
+ repositionPopup(node);
82
+ continue;
83
+ }
84
+ // Also handle nested cases where the popup is not the direct added node
85
+ const popup = node.querySelector('div[style*="position:absolute"][style*="display:grid"][style*="top:-1em"]');
86
+ if (popup) repositionPopup(popup);
87
+ }
88
+ }
89
+ });
90
+ observer.observe(div, {
91
+ childList: true,
92
+ subtree: true
93
+ });
28
94
  } // renderForm
29
95
 
96
+ function enableFocusOnAdd(root) {
97
+ const PLUS_ICON = 'noun_19460_green.svg';
98
+ const isAddButton = el => {
99
+ const img = el.querySelector('img');
100
+ const label = el.querySelector('span');
101
+ return img?.src.includes(PLUS_ICON) && label?.textContent?.trim().toLowerCase().startsWith('add ');
102
+ };
103
+ const buttons = Array.from(root.querySelectorAll('div')).filter(isAddButton);
104
+ buttons.forEach(btn => {
105
+ btn.addEventListener('click', () => {
106
+ const scope = function findScope(el) {
107
+ let cur = el;
108
+ while (cur && cur !== root) {
109
+ if (cur.querySelector('input[data-testid="autocomplete-input"]')) return cur;
110
+ cur = cur.parentElement;
111
+ }
112
+ return root;
113
+ }(btn);
114
+ const before = new Set(Array.from(scope.querySelectorAll('input[data-testid="autocomplete-input"]')));
115
+ const start = Date.now();
116
+ const interval = setInterval(() => {
117
+ const current = Array.from(scope.querySelectorAll('input[data-testid="autocomplete-input"]'));
118
+ const newInput = current.find(el => !before.has(el));
119
+ if (newInput) {
120
+ // New inputs are usually wrapped in a label/link; make sure focus jumps
121
+ // straight to the input rather than the label link.
122
+ skipLabelsFromTabbing(scope);
123
+ newInput.focus();
124
+ clearInterval(interval);
125
+ return;
126
+ }
127
+ if (Date.now() - start > 1000) {
128
+ clearInterval(interval);
129
+ }
130
+ }, 50);
131
+ });
132
+ });
133
+ }
134
+
30
135
  // we need to load into the store some additional information about Social Media accounts
31
136
  function loadDocument(store, documentSource, documentName, documentURI) {
32
137
  const finalDocumentUri = documentURI || baseUri + documentName; // Full URI to the file
@@ -37,4 +142,24 @@ function loadDocument(store, documentSource, documentName, documentURI) {
37
142
  // the form can be used for both use cases: create UI for edit and render UI for display
38
143
  (0, _rdflib.parse)(documentSource, store, finalDocumentUri, 'text/turtle', () => null); // Load doc directly
39
144
  }
145
+ }
146
+ function skipLabelsFromTabbing(root) {
147
+ // Many Solid-UI forms render field labels as focusable links (hrefs).
148
+ // Make sure keyboard tabbing skips these label links entirely.
149
+ const selectors = ['label', '.formFieldName a', '.classifierBox-label a', '.choiceBox-label a', '.label a',
150
+ // Skip focusable label-like links created by Solid-UI forms, including the vcard note link
151
+ 'a[href="http://www.w3.org/2006/vcard/ns#note"]', 'a[href$="#note"]'].join(', ');
152
+
153
+ // querySelectorAll<HTMLElement> ensures the elements are typed correctly so we can access tabIndex.
154
+ const nodes = root?.querySelectorAll(selectors);
155
+ if (!nodes) return;
156
+ Array.from(nodes).forEach(el => {
157
+ if (typeof el.tabIndex === 'number' && el.tabIndex !== -1) {
158
+ el.tabIndex = -1;
159
+ }
160
+ // Ensure those label links are not announced as focusable elements
161
+ if (el.getAttribute('aria-hidden') !== 'true') {
162
+ el.setAttribute('aria-hidden', 'true');
163
+ }
164
+ });
40
165
  }
@@ -69,6 +69,12 @@
69
69
  min-width: 0;
70
70
  }
71
71
 
72
+ /* Ensure prompt inputs stretch to fit their container */
73
+ .add-friend-button-container input[type="text"] {
74
+ width: 100%;
75
+ box-sizing: border-box;
76
+ }
77
+
72
78
  .qrCodeSection {
73
79
  color: var(--color-text-secondary);
74
80
  font-size: 1em;
@@ -1,22 +1,20 @@
1
1
  /* ProfileView.css */
2
2
  /* Uses utilities: .section-bg, .text-center */
3
3
 
4
- .profileSection {
5
-
6
- }
7
-
8
4
  /* Horizontal layout for cards */
9
5
  .profile-grid .profileSection {
10
6
  width: 100%;
11
7
  max-width: 100%;
8
+ min-width: 0;
12
9
  box-sizing: border-box;
13
10
  margin-bottom: var(--spacing-md);
14
11
  box-sizing: border-box;
15
12
  margin-bottom: var(--spacing-md);
13
+ overflow-wrap: anywhere;
16
14
  }
17
15
 
18
16
  @media (min-width: 900px) {
19
- .profileSection {
17
+ .profile-grid .profileSection {
20
18
  margin-bottom: 0;
21
19
  }
22
20
  }
@@ -0,0 +1,62 @@
1
+ .profile-grid .add-friend-button-container,
2
+ .profile-grid .add-community-button-container {
3
+ display: inline-flex;
4
+ align-items: center;
5
+ gap: var(--spacing-xxs);
6
+ flex-wrap: wrap;
7
+ justify-content: flex-start;
8
+ }
9
+
10
+ /* Ensure the button container can shrink properly in narrow layouts */
11
+ .profile-grid .add-community-button-container {
12
+ min-width: 0;
13
+ max-width: 100%;
14
+ }
15
+
16
+ /* Allow any direct children to shrink so no element forces overflow */
17
+ .profile-grid .add-community-button-container > * {
18
+ min-width: 0;
19
+ max-width: 100%;
20
+ }
21
+
22
+ .profile-grid table {
23
+ margin: 0 !important;
24
+ }
25
+
26
+ .profile-grid td {
27
+ padding: 0;
28
+ }
29
+
30
+ .profile-grid .add-friend-button-container .span,
31
+ .profile-grid .add-community-button-container .span {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ }
35
+
36
+ .profile-grid .add-friend-button-container > div,
37
+ .profile-grid .add-community-button-container > div {
38
+ flex-basis: 100%;
39
+ }
40
+
41
+ /* Prevent the add-community input from overflowing its flex container */
42
+ .profile-grid .add-community-button-container input {
43
+ min-width: 0;
44
+ max-width: 96%;
45
+ flex: 1 1 0;
46
+ word-break: break-word;
47
+ }
48
+
49
+ .profile-grid .profile-image {
50
+ width: var( --profile-image-size);
51
+ height: var( --profile-image-size);
52
+ margin: var(--spacing-xxxs);
53
+ border-radius: var(--spacing-lg);
54
+ }
55
+
56
+ .profile-grid .default-profile-image {
57
+ width: 140%;
58
+ height: 140%;
59
+ object-fit: cover;
60
+ margin-left: -0.6em;
61
+ border-radius: var(--spacing-lg);
62
+ }
@@ -0,0 +1,427 @@
1
+ /* Delete pop up*/
2
+ /* Make the Solid-UI delete confirmation popup appear near the last click position.
3
+ Keep the built-in Solid-UI styling (orange border, white background) so it looks like the original.
4
+ */
5
+ .profile-grid div[style*="position: relative"] > div[style*="display: grid"] {
6
+ /* only override positioning; keep styling (border/background/etc) from solid-ui */
7
+ position: absolute !important;
8
+ z-index: 9999 !important;
9
+ top: 0 !important;
10
+ right: 0 !important;
11
+ left: auto !important;
12
+ display: grid !important;
13
+ pointer-events: auto !important;
14
+ opacity: 1 !important;
15
+ visibility: visible !important;
16
+ padding: 0.7em !important;
17
+ min-width: 280px !important;
18
+ max-width: 90vw !important;
19
+ background: var(--color-background) !important;
20
+ border: 0.1em solid var(--color-primary) !important;
21
+ border-radius: var(--border-radius-base) !important;
22
+ box-shadow: 0 0.5em 0.9em rgba(0, 0, 0, 0.2) !important;
23
+ grid-template-columns: auto auto !important;
24
+ gap: 0.3em !important;
25
+ }
26
+
27
+ /* Ensure SVG icons and their buttons inside the Solid-UI delete popup have transparent backgrounds */
28
+ .profile-grid div[style*="position: relative"] > div[style*="display: grid"] img[src$=".svg"],
29
+ .profile-grid div[style*="position: relative"] > div[style*="display: grid"] button {
30
+ background: transparent !important;
31
+ }
32
+
33
+ .profile-form .individualPane {
34
+ box-shadow: none !important;
35
+ }
36
+
37
+ .profile-form p {
38
+ padding: 0 !important;
39
+ }
40
+
41
+ .profile-form .mb-md {
42
+ margin-bottom: 0 !important;
43
+ }
44
+
45
+ .profile-form h2 {
46
+ margin-bottom: 1em !important;
47
+ }
48
+
49
+ .profile-form h3 {
50
+ color: var(--color-primary) !important;
51
+ padding: 0 !important;
52
+ font-size: 1em !important;
53
+ font-weight: 600 !important;
54
+ }
55
+
56
+ /* Shared form layout rules are imported from rdfFormsCommon.css */
57
+ /* Solid-UI form sizing fixes scoped to Edit CV section */
58
+ .profile-form .hoverControl:not(:has(> img:first-child)) {
59
+ border: 0.1em solid rgb(136, 136, 136) !important;
60
+ flex-direction: column !important;
61
+ }
62
+
63
+ .profile-form .hoverControl:has(> img:first-child) {
64
+ background-color: transparent !important;
65
+ border: none !important;
66
+ margin: 0 !important;
67
+ border-radius: 0 !important;
68
+ padding: 0.7em !important;
69
+ min-height: var(--min-touch-target);
70
+ min-width: var(--min-touch-target);
71
+ cursor: pointer;
72
+ display: inline-flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ }
76
+
77
+ /* Make sure the delete icon floats in the top-right corner of the full hoverControl wrapper */
78
+ .profile-form .hoverControl,
79
+ .profile-grid .hoverControl {
80
+ position: relative !important;
81
+ }
82
+
83
+ .hoverControl > img.hoverControlHide,
84
+ .hoverControl > [data-testid="deleteButtonWithCheck"] {
85
+ position: absolute !important;
86
+ top: 0.2em !important;
87
+ right: 0.2em !important;
88
+ width: 1.5em !important;
89
+ height: 1.5em !important;
90
+ align-items: center;
91
+ justify-content: center;
92
+ margin: 0 !important;
93
+ float: none !important;
94
+ transform: none !important;
95
+ }
96
+
97
+ /* When icon is 2nd or 3rd child (i.e. sibling elements exist), align it vertically to the previous item */
98
+ .hoverControl > img.hoverControlHide:nth-child(1),
99
+ .hoverControl > img.hoverControlHide:nth-child(2),
100
+ .hoverControl > [data-testid="deleteButtonWithCheck"]:nth-child(1),
101
+ .hoverControl > [data-testid="deleteButtonWithCheck"]:nth-child(2) {
102
+ top: 50% !important;
103
+ transform: translateY(-50%) !important;
104
+ display: inline-flex !important;
105
+ }
106
+
107
+ /* Show the delete icon only when the container is hovered */
108
+ .profile-grid .hoverControl:hover > img.hoverControlHide,
109
+ .profile-grid .hoverControl:hover > [data-testid="deleteButtonWithCheck"] {
110
+ display: inline-flex !important;
111
+ }
112
+
113
+ /* Also show the delete icon when the entire row is hovered */
114
+ .profile-grid .attachmentTable tr:hover .hoverControl > img.hoverControlHide,
115
+ .profile-grid .attachmentTable tr:hover .hoverControl > [data-testid="deleteButtonWithCheck"] {
116
+ display: inline-flex !important;
117
+ }
118
+
119
+ /* Make the hover-control cell easier to hit */
120
+ .profile-grid .hoverControl {
121
+ padding: 0.75em !important;
122
+ min-width: 2.5em !important;
123
+ min-height: 2.5em !important;
124
+ }
125
+
126
+ /* When the hoverControl only contains the hidden delete icon, keep it out of layout so it doesn't create empty space */
127
+ .profile-form .formFieldValue .hoverControl:has(> img.hoverControlHide) {
128
+ min-width: 0 !important;
129
+ min-height: 0 !important;
130
+ width: 0 !important;
131
+ height: 0 !important;
132
+ padding: 0 !important;
133
+ margin: 0 !important;
134
+ overflow: visible !important;
135
+ }
136
+
137
+ /* Hide delete icon only in autocomplete fields */
138
+ .profile-grid .formFieldValue:has(input[data-testid="autocomplete-input"]) [data-testid="delete-button"] {
139
+ display: none !important;
140
+ }
141
+
142
+ /* Keep autocomplete cancel button hidden when the user is not interacting.
143
+ This avoids the cancel button remaining visible when focus moves away. */
144
+ .profile-grid .formFieldValue:not(:focus-within) [data-testid="cancel-button"] {
145
+ display: none !important;
146
+ }
147
+
148
+ .profile-grid .hoverControl:has(> img:first-child) > span {
149
+ display: inline-flex;
150
+ align-items: center;
151
+ margin-left: 0.3em;
152
+ }
153
+
154
+ .profile-grid div[style*="padding: 0.5em"]:has(> img) > span {
155
+ margin-left: 0.3em;
156
+ vertical-align: super !important;
157
+ }
158
+
159
+ .profile-grid .hoverControl:has(> img:first-child):hover {
160
+ background-color: transparent !important;
161
+ }
162
+
163
+ .profile-grid button:has(> img[src$=".svg"]),
164
+ .profile-grid .formFieldValue input[type ="color"] {
165
+ background-color: var(--color-section-bg) !important;
166
+ border: none !important;
167
+ margin: 0 !important;
168
+ border-radius: 0 !important;
169
+ box-shadow: none !important;
170
+ padding: 0.5em !important;
171
+ transition: background-color 0.2s ease, box-shadow 0.2s ease;
172
+ padding: 0 !important;
173
+ }
174
+
175
+ /* Specific icon button should have no extra padding */
176
+ .profile-grid button:has(> img[src="https://solidos.github.io/solid-ui/src/icons/noun_1369241.svg"]) {
177
+ padding: 0 !important;
178
+ }
179
+
180
+ .profile-form button {
181
+ min-height: var(--min-touch-target);
182
+ min-width: var(--min-touch-target);
183
+ }
184
+
185
+ .profile-form input:not([type="color"]) {
186
+ width: 99%;
187
+ margin-left: 0 !important;
188
+ margin-right: 0 !important;
189
+ }
190
+
191
+ .profile-form input:not([type="color"]),
192
+ .profile-form textarea,
193
+ .profile-form select {
194
+ max-width: 96%;
195
+ min-width: 0;
196
+ box-sizing: border-box ;
197
+ font: inherit;
198
+ color: var(--color-text);
199
+ background-color: var(--color-card-bg) !important;
200
+ border: 1px solid var(--color-border-pale);
201
+ }
202
+
203
+ .profile-form textarea {
204
+ border-color: var(--color-border-pale) !important;
205
+ }
206
+
207
+ .profile-form input[type="date"],
208
+ .profile-form input[type="month"],
209
+ .profile-form input[type="week"],
210
+ .profile-form input[type="time"],
211
+ .profile-form input[type="datetime-local"] {
212
+ min-height: var(--min-touch-target);
213
+ }
214
+
215
+ .profile-form .hoverControl:has(> img:first-child):focus-visible,
216
+ .profile-form button:focus-visible,
217
+ .profile-form input:not([type="color"]):focus-visible,
218
+ .profile-form textarea:focus-visible,
219
+ .profile-form select:focus-visible {
220
+ outline: var(--focus-ring-width) solid var(--color-primary) !important;
221
+ outline-offset: 2px;
222
+ box-shadow: 0 0 0 1px var(--color-background);
223
+ }
224
+
225
+ .profile-form input[type="url"] {
226
+ width: 100%;
227
+ }
228
+
229
+ .profile-form select#formSelect {
230
+ width: 100%;
231
+ max-width: 97%;
232
+ box-sizing: border-box;
233
+ margin-left: 0 !important;
234
+ margin-right: 0 !important;
235
+ }
236
+
237
+ /* Remove border/padding from the first wrapper div (and its first child wrapper). */
238
+ .profile-form > div:first-of-type,
239
+ .profile-form > div:first-of-type > div:first-of-type {
240
+ border: none !important;
241
+ padding: 0 !important;
242
+ }
243
+
244
+ /* Remove border/padding from the inner div of the first wrapper in the contact section. */
245
+ section[aria-labelledby="edit-profile-contact-heading"] .profile-form > div:first-of-type > div:first-of-type {
246
+ border: none !important;
247
+ padding: 0 !important;
248
+ }
249
+
250
+ /* In contactPane, remove border/padding from all direct child divs. */
251
+ .contactPane > div {
252
+ border: none !important;
253
+ padding: 0 !important;
254
+ }
255
+
256
+ /* Align schema.org, solid terms, FOAF, vCard, and org field labels with their input values. */
257
+ .profile-form :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) {
258
+ display: flex;
259
+ }
260
+
261
+ /* for the Resume inside corporation choice */
262
+ /* Add space between classifierBox label and select box */
263
+ .profile-form .choiceBox .classifierBox-label {
264
+ /* Optional: ensure label doesn't have extra margin */
265
+ margin-right: 0;
266
+ padding-left: 0.3em;
267
+ }
268
+ .profile-form .choiceBox .choiceBox-selectBox select {
269
+ margin-left: 2.1em !important;
270
+ }
271
+
272
+ /* for the Resume orga details */
273
+ /* Add space between classifierBox label and select box */
274
+ .profile-form .classifierBox .classifierBox-label {
275
+ /* Match .formFieldName for alignment */
276
+ margin-right: 0;
277
+ padding-left: 0.3em;
278
+ width: 8em;
279
+ padding: 0.3em;
280
+ vertical-align: middle;
281
+ }
282
+ .profile-form .classifierBox .classifierBox-selectBox {
283
+ margin-left: 0 !important;
284
+ }
285
+
286
+ .profile-form .classifierBox .classifierBox-selectBox select {
287
+ margin-left: 0 !important;
288
+ }
289
+
290
+ /* for the social media */
291
+ /* Add space between classifierBox label and select box */
292
+ section[data-testid="edit-social-section"] .classifierBox-label {
293
+ /* Optional: ensure label doesn't have extra margin */
294
+ margin-right: 0;
295
+ padding-left: 0.3em;
296
+ }
297
+ section[data-testid="edit-social-section"] .classifierBox-selectBox select {
298
+ margin-left: 0.7em !important;
299
+ }
300
+
301
+ .profile-form :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue {
302
+ margin-bottom: 0;
303
+ }
304
+
305
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://schema.org/"]),
306
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://www.w3.org/ns/solid/terms#"]),
307
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://xmlns.com/foaf/0.1/"]),
308
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://www.w3.org/2006/vcard/ns"]),
309
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://www.w3.org/ns/org#"]) {
310
+ display: inline-flex;
311
+ align-items: center;
312
+ vertical-align: middle;
313
+ }
314
+
315
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://schema.org/"]) + .formFieldValue,
316
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://www.w3.org/ns/solid/terms#"]) + .formFieldValue,
317
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://xmlns.com/foaf/0.1/"]) + .formFieldValue,
318
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://www.w3.org/2006/vcard/ns"]) + .formFieldValue,
319
+ .profile-form :not(.choiceBox) > .formFieldName:has(a[href*="http://www.w3.org/ns/org#"]) + .formFieldValue {
320
+ display: inline-flex;
321
+ align-items: center;
322
+ vertical-align: middle;
323
+ flex: 1;
324
+ min-width: 0;
325
+ }
326
+
327
+ .profile-form textarea,
328
+ .profile-form .formFieldValue textarea {
329
+ appearance: none;
330
+ -webkit-appearance: none;
331
+ border: .05em solid #88c !important;
332
+ border-style: solid !important;
333
+ border-width: .05em !important;
334
+ border-color: #88c !important;
335
+ border-radius: 0.2em !important;
336
+ width: 99%;
337
+ box-sizing: border-box;
338
+ margin-top: var(--spacing-xs);
339
+ margin-left: 0 !important;
340
+ margin-right: 0 !important;
341
+ }
342
+
343
+ /* Add horizontal gap between label and textarea for all label+textarea pairs. */
344
+ .profile-form div:has(> a) + div:has(textarea) {
345
+ margin-left: var(--spacing-sm);
346
+ }
347
+
348
+ /* Center textarea label vertically in flex rows. */
349
+ .profile-form div[style*="display: flex"][style*="flex-direction: row"]:has(textarea) {
350
+ align-items: flex-start;
351
+ }
352
+
353
+ .profile-form div[style*="display: flex"][style*="flex-direction: row"]:has(textarea) > div:has(> a) {
354
+ padding-left: var(--spacing-xs);
355
+ padding-top: var(--spacing-sm);
356
+ }
357
+
358
+
359
+ .profile-form :not(.choiceBox):has(> .formFieldValue input[data-testid="autocomplete-input"]) > .formFieldName {
360
+ padding-top: 0.55em !important;
361
+ }
362
+
363
+
364
+ .profile-form input:disabled,
365
+ .profile-form textarea:disabled,
366
+ .profile-form select:disabled,
367
+ .profile-form input[readonly],
368
+ .profile-form textarea[readonly],
369
+ .profile-form input:read-only,
370
+ .profile-form textarea:read-only {
371
+ background-color: var(--color-background) !important;
372
+ cursor: not-allowed;
373
+ opacity: 0.75;
374
+ border: 0.05em solid white !important;
375
+ }
376
+
377
+ .webidControl table td div.contactPane.namedPane {
378
+ border: none !important;
379
+ }
380
+
381
+ /* Hide the edit icon used by solid-ui (noun_253504.svg and noun_1180158.svg) when it appears as an <img> */
382
+ img[src*="noun_253504.svg"],
383
+ img[src*="noun_1180158.svg"] {
384
+ display: none !important;
385
+ width: 0 !important;
386
+ height: 0 !important;
387
+ margin: 0 !important;
388
+ padding: 0 !important;
389
+ }
390
+
391
+ /* Ensure the parent button for that icon doesn't add padding/margin or affect layout */
392
+ button:has(> img[src*="noun_253504.svg"]),
393
+ button:has(> img[src*="noun_1180158.svg"]) {
394
+ display: none !important;
395
+ padding: 0 !important;
396
+ margin: 0 !important;
397
+ border: none !important;
398
+ background: none !important;
399
+ width: 0 !important;
400
+ height: 0 !important;
401
+ overflow: hidden !important;
402
+ }
403
+
404
+ /* Exceptions: allow these icons (and their buttons) when they're part of the add-friend or add-community flows. */
405
+ .profile-grid .profileSection .add-friend-button-container img[src="https://solidos.github.io/solid-ui/src/icons/noun_253504.svg"],
406
+ .profile-grid .profileSection .add-community-button-container img[src="https://solidos.github.io/solid-ui/src/icons/noun_253504.svg"],
407
+ .profile-grid .profileSection .add-friend-button-container button:has(> img[src="https://solidos.github.io/solid-ui/src/icons/noun_253504.svg"]),
408
+ .profile-grid .profileSection .add-community-button-container button:has(> img[src="https://solidos.github.io/solid-ui/src/icons/noun_253504.svg"]) {
409
+ display: inline-flex !important;
410
+ width: auto !important;
411
+ height: auto !important;
412
+ overflow: visible !important;
413
+ }
414
+
415
+
416
+ /* Exception: allow “Continue” buttons inside add-friend and add-community button containers. */
417
+ .profile-grid .profileSection .add-friend-button-container button:has(> img[title="Continue"]),
418
+ .profile-grid .profileSection .add-community-button-container button:has(> img[title="Continue"]),
419
+ .profile-grid .profileSection .add-friend-button-container button:has(> img[src="https://solidos.github.io/solid-ui/src/icons/noun_1180158.svg"]),
420
+ .profile-grid .profileSection .add-community-button-container button:has(> img[src="https://solidos.github.io/solid-ui/src/icons/noun_1180158.svg"]),
421
+ .profile-grid .profileSection .add-friend-button-container img[src="https://solidos.github.io/solid-ui/src/icons/noun_1180158.svg"],
422
+ .profile-grid .profileSection .add-community-button-container img[src="https://solidos.github.io/solid-ui/src/icons/noun_1180158.svg"] {
423
+ display: inline-flex !important;
424
+ width: 2em !important;
425
+ height: 2em !important;
426
+ overflow: visible !important;
427
+ }