fix(nubus): Replace openDesk portal fork with upstream portal-frontend image

This commit is contained in:
Thorsten Roßner
2025-06-06 07:55:19 +02:00
parent 19f4ea90e2
commit e4f1afca0f
17 changed files with 224 additions and 11 deletions

View File

@@ -20,6 +20,11 @@ Please review the default configuration that is applied to understand your custo
You can just update the files in [helmfile/files/theme](../helmfile/files/theme) to change logos, favicons etc. Note that the `.svg` versions of the favicons are also used for the portal tiles. You can just update the files in [helmfile/files/theme](../helmfile/files/theme) to change logos, favicons etc. Note that the `.svg` versions of the favicons are also used for the portal tiles.
> **Note**<br>
> Theming focusses on colors, iconography and imagery. If you like to adapt the default links in the portal pointing to external
> resources (like "Support", "Legal Notice") please check the `functional.portal` section
> in [`functional.yaml.gotmpl`](../helmfile/environments/default/functional.yaml.gotmpl)
# Known limitations # Known limitations
- Portal and Keycloak screen styles, especially colors, must be applied in the [`portalStylesheets.css`](../helmfile/files/theme/portalStylesheet.css), - Portal and Keycloak screen styles, especially colors, must be applied in the [`portalStylesheets.css`](../helmfile/files/theme/portalStylesheet.css),

View File

@@ -409,8 +409,12 @@ nubusPortalFrontend:
portalFrontend: portalFrontend:
branding: branding:
css: {{ .Values.theme.styles.portal.main | toJson }} css: {{ .Values.theme.styles.portal.main | toJson }}
# Requires .ico, .svg does not work.
favicon: {{ .Values.theme.imagery.portal.faviconIco | toJson }} favicon: {{ .Values.theme.imagery.portal.faviconIco | toJson }}
faviconSvg: {{ .Values.theme.imagery.portal.faviconSvg | toJson }}
favicon96Png: {{ .Values.theme.imagery.portal.favicon96Png | toJson }}
appleTouchIcon: {{ .Values.theme.imagery.portal.appleTouchIcon | toJson }}
webManifestIcon192: {{ .Values.theme.imagery.portal.webManifestIcon192 | toJson }}
webManifestIcon512: {{ .Values.theme.imagery.portal.webManifestIcon512 | toJson }}
# The actual `logo` is set in customizing image, the logo down here is for waiting spinner. # The actual `logo` is set in customizing image, the logo down here is for waiting spinner.
logo: {{ .Values.theme.imagery.portal.waitingSpinnerSvg | toJson }} logo: {{ .Values.theme.imagery.portal.waitingSpinnerSvg | toJson }}
backgroundImage: {{ .Values.theme.imagery.portal.backgroundSvg | toJson }} backgroundImage: {{ .Values.theme.imagery.portal.backgroundSvg | toJson }}
@@ -680,7 +684,6 @@ nubusPortalServer:
{{- with .Values.annotations.nubusPortalServer.ingress }} {{- with .Values.annotations.nubusPortalServer.ingress }}
{{ . | toYaml | nindent 8 }} {{ . | toYaml | nindent 8 }}
{{- end }} {{- end }}
certManager: certManager:
enabled: false enabled: false
tls: tls:
@@ -704,6 +707,25 @@ nubusPortalServer:
sharedSecret: {{ .Values.secrets.centralnavigation.apiKey | quote }} sharedSecret: {{ .Values.secrets.centralnavigation.apiKey | quote }}
featureToggles: featureToggles:
notifications_api: false notifications_api: false
centered_layout: true
newsfeed: {{ .Values.apps.xwiki.enabled }}
umc_session_refresh: true
welcome_message: true
newsfeed:
feedType: "xwiki"
feedUrl:
en_US: {{ printf "https://%s.%s/wiki/bin/get/Blog/BlogRss?xpage=plain&blog=openDesk.Newsfeed.WebHome" .Values.global.hosts.intercomService .Values.global.domain }}
de_DE: {{ printf "https://%s.%s/wiki/bin/get/Blog/BlogRss?xpage=plain&blog=openDesk.Newsfeed.WebHome" .Values.global.hosts.intercomService .Values.global.domain }}
homeUrl:
en_US: {{ printf "https://%s.%s/bin/view/openDesk/Newsfeed/" .Values.global.hosts.xwiki .Values.global.domain }}
de_DE: {{ printf "https://%s.%s/bin/view/openDesk/Newsfeed/" .Values.global.hosts.xwiki .Values.global.domain }}
icsSilentLoginUrl: {{ printf "https://%s.%s/silent" .Values.global.hosts.intercomService .Values.global.domain }}
objectStorageEndpoint: {{ printf "https://%s" (.Values.objectstores.nubus.endpoint | default (printf "%s.%s" .Values.global.hosts.minioApi .Values.global.domain)) | quote }}
objectStorageBucket: {{ .Values.objectstores.nubus.bucket | quote }}
objectStorageCredentialSecret:
name: "ums-portal-server-minio-opendesk-credentials"
accessKeyKey: "access-key-id"
secretKeyKey: "secret-key-id"
replicaCount: {{ .Values.replicas.umsPortalServer }} replicaCount: {{ .Values.replicas.umsPortalServer }}
resources: resources:
{{ .Values.resources.umsPortalServer | toYaml | nindent 4 }} {{ .Values.resources.umsPortalServer | toYaml | nindent 4 }}

View File

@@ -550,7 +550,7 @@ images:
# upstreamRepository: "bmi/opendesk/components/platform-development/images/opendesk-nubus" # upstreamRepository: "bmi/opendesk/components/platform-development/images/opendesk-nubus"
registry: "registry.opencode.de" registry: "registry.opencode.de"
repository: "bmi/opendesk/components/platform-development/images/opendesk-nubus" repository: "bmi/opendesk/components/platform-development/images/opendesk-nubus"
tag: "1.14.4@sha256:cf0e22c1eef138a413a90a60c5405126dc769195dd4dd37229a27afaa82ef3b3" tag: "1.14.7@sha256:e00b6829b765dc1319593c1a1f8369950fc179308d65b79838539ca2967eb5ac"
nubusOpendeskExtensionA2gMapper: nubusOpendeskExtensionA2gMapper:
# providerCategory: "Platform" # providerCategory: "Platform"
# providerResponsible: "openDesk" # providerResponsible: "openDesk"
@@ -604,9 +604,11 @@ images:
# providerResponsible: "Univention" # providerResponsible: "Univention"
# upstreamRegistry: "https://artifacts.software-univention.de" # upstreamRegistry: "https://artifacts.software-univention.de"
# upstreamRepository: "nubus/images/portal-frontend" # upstreamRepository: "nubus/images/portal-frontend"
# upstreamMirrorTagFilterRegEx: '^(\d+)\.(\d+)\.(\d+)$'
# upstreamMirrorStartFrom: ["0", "67", "0"]
registry: "registry.opencode.de" registry: "registry.opencode.de"
repository: "bmi/opendesk/components/platform-development/images/opendesk-nubus-portal-update" repository: "bmi/opendesk/components/supplier/univention/images-mirror/portal-frontend"
tag: "1.10.14@sha256:fbdec057958fd7e728431cf96896b8453c2f5b390ce3d2f169a7766f49926b1b" tag: "0.70.0@sha256:9e0826c954e99b36b3c7b9ce6dfa1f567a3432158fb78af13337760197f94997"
nubusPortalServer: nubusPortalServer:
# providerCategory: "Supplier" # providerCategory: "Supplier"
# providerResponsible: "Univention" # providerResponsible: "Univention"

View File

@@ -66,7 +66,13 @@ theme:
faviconIco: {{ readFile "./../../files/theme/notes/favicon.ico" | b64enc | quote }} faviconIco: {{ readFile "./../../files/theme/notes/favicon.ico" | b64enc | quote }}
portal: portal:
faviconIco: {{ readFile "./../../files/theme/portal/favicon.ico" | b64enc | quote }} faviconIco: {{ readFile "./../../files/theme/portal/favicon/favicon.ico" | b64enc | quote }}
faviconSvg: {{ readFile "./../../files/theme/portal/favicon/favicon.svg" | b64enc | quote }}
favicon96Png: {{ readFile "./../../files/theme/portal/favicon/favicon-96x96.png" | b64enc | quote }}
appleTouchIcon: {{ readFile "./../../files/theme/portal/favicon/apple-touch-icon.png" | b64enc | quote }}
webManifestIcon192: {{ readFile "./../../files/theme/portal/favicon/web-app-manifest-192x192.png" | b64enc | quote }}
webManifestIcon512: {{ readFile "./../../files/theme/portal/favicon/web-app-manifest-512x512.png" | b64enc | quote }}
waitingSpinnerSvg: {{ readFile "./../../files/theme/portal/waiting-spinner.svg" | b64enc }} waitingSpinnerSvg: {{ readFile "./../../files/theme/portal/waiting-spinner.svg" | b64enc }}
backgroundSvg: {{ readFile "./../../files/theme/portal/background.svg" | b64enc | quote }} backgroundSvg: {{ readFile "./../../files/theme/portal/background.svg" | b64enc | quote }}
portalTiles: portalTiles:
@@ -89,6 +95,10 @@ theme:
notes: {{ readFile "./../../files/theme/notes/favicon.svg" | b64enc | quote }} notes: {{ readFile "./../../files/theme/notes/favicon.svg" | b64enc | quote }}
realtimeCollaboration: {{ readFile "./../../files/theme/chat/favicon.svg" | b64enc | quote }} realtimeCollaboration: {{ readFile "./../../files/theme/chat/favicon.svg" | b64enc | quote }}
realtimeVideoconference: {{ readFile "./../../files/theme/videoconference/favicon.svg" | b64enc | quote }} realtimeVideoconference: {{ readFile "./../../files/theme/videoconference/favicon.svg" | b64enc | quote }}
# links
documentation: {{ readFile "./../../files/theme/link_documentation/favicon.svg" | b64enc | quote }}
feedback: {{ readFile "./../../files/theme/link_feedback/favicon.svg" | b64enc | quote }}
support: {{ readFile "./../../files/theme/link_support/favicon.svg" | b64enc | quote }}
# empty.svg # empty.svg
empty: {{ readFile "./../../files/theme/_dev/empty.svg" | b64enc | quote }} empty: {{ readFile "./../../files/theme/_dev/empty.svg" | b64enc | quote }}
fileshareActivity: {{ readFile "./../../files/theme/_dev/empty.svg" | b64enc | quote }} fileshareActivity: {{ readFile "./../../files/theme/_dev/empty.svg" | b64enc | quote }}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none" class="portal-help__icon"><mask id="mask0_406_2939" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20" style="mask-type: alpha;"><rect width="20" height="20" fill="#D9D9D9"></rect></mask><g mask="url(#mask0_406_2939)"><path d="M9.9987 16.666C9.33203 16.1382 8.60981 15.7285 7.83203 15.4368C7.05425 15.1452 6.2487 14.9993 5.41536 14.9993C4.83203 14.9993 4.25911 15.0757 3.69661 15.2285C3.13411 15.3813 2.59592 15.5966 2.08203 15.8743C1.79036 16.0271 1.50911 16.0202 1.23828 15.8535C0.967448 15.6868 0.832031 15.4438 0.832031 15.1243V5.08268C0.832031 4.9299 0.870226 4.78407 0.946615 4.64518C1.023 4.50629 1.13759 4.40213 1.29036 4.33268C1.92925 3.99935 2.59592 3.74935 3.29036 3.58268C3.98481 3.41602 4.69314 3.33268 5.41536 3.33268C6.22092 3.33268 7.00912 3.43685 7.77995 3.64518C8.55078 3.85352 9.29037 4.16602 9.9987 4.58268V14.666C10.707 14.2216 11.4501 13.8882 12.2279 13.666C13.0056 13.4438 13.7904 13.3327 14.582 13.3327C15.082 13.3327 15.5716 13.3743 16.0508 13.4577C16.5299 13.541 17.0126 13.666 17.4987 13.8327V3.83268C17.707 3.90213 17.9119 3.97504 18.1133 4.05143C18.3147 4.12782 18.5126 4.22157 18.707 4.33268C18.8598 4.40213 18.9744 4.50629 19.0508 4.64518C19.1272 4.78407 19.1654 4.9299 19.1654 5.08268V15.1243C19.1654 15.4438 19.0299 15.6868 18.7591 15.8535C18.4883 16.0202 18.207 16.0271 17.9154 15.8743C17.4015 15.5966 16.8633 15.3813 16.3008 15.2285C15.7383 15.0757 15.1654 14.9993 14.582 14.9993C13.7487 14.9993 12.9431 15.1452 12.1654 15.4368C11.3876 15.7285 10.6654 16.1382 9.9987 16.666ZM11.6654 12.4993V4.58268L15.832 0.416016V8.74935L11.6654 12.4993ZM8.33203 13.8535V5.60352C7.8737 5.40907 7.398 5.25977 6.90495 5.1556C6.41189 5.05143 5.91536 4.99935 5.41536 4.99935C4.90148 4.99935 4.40148 5.04796 3.91536 5.14518C3.42925 5.2424 2.95703 5.38824 2.4987 5.58268V13.8535C2.98481 13.673 3.46745 13.541 3.94661 13.4577C4.42578 13.3743 4.91536 13.3327 5.41536 13.3327C5.91536 13.3327 6.40495 13.3743 6.88412 13.4577C7.36328 13.541 7.84592 13.673 8.33203 13.8535Z" fill="white"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20" fill="none" class="portal-help__icon"><mask id="mask0_592_612" maskUnits="userSpaceOnUse" x="0" y="0" width="21" height="20" style="mask-type: alpha;"><rect x="0.644531" width="20" height="20" fill="#D9D9D9"></rect></mask><g mask="url(#mask0_592_612)"><path d="M18.9792 18.3337L15.6458 15.0003H3.97917C3.52083 15.0003 3.12847 14.8371 2.80208 14.5107C2.47569 14.1844 2.3125 13.792 2.3125 13.3337V3.33366C2.3125 2.87533 2.47569 2.48296 2.80208 2.15658C3.12847 1.83019 3.52083 1.66699 3.97917 1.66699H17.3125C17.7708 1.66699 18.1632 1.83019 18.4896 2.15658C18.816 2.48296 18.9792 2.87533 18.9792 3.33366V18.3337ZM3.97917 13.3337H16.3542L17.3125 14.2712V3.33366H3.97917V13.3337Z" fill="white"></path></g></svg>

After

Width:  |  Height:  |  Size: 789 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none" class="portal-help__icon"><mask id="mask0_406_2944" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20" style="mask-type: alpha;"><rect width="20" height="20" fill="#D9D9D9"></rect></mask><g mask="url(#mask0_406_2944)"><path d="M10 18.3327L9.79167 15.8327H9.58333C7.61111 15.8327 5.9375 15.1452 4.5625 13.7702C3.1875 12.3952 2.5 10.7216 2.5 8.74935C2.5 6.77713 3.1875 5.10352 4.5625 3.72852C5.9375 2.35352 7.61111 1.66602 9.58333 1.66602C10.5694 1.66602 11.4896 1.85004 12.3438 2.2181C13.1979 2.58615 13.9479 3.0931 14.5938 3.73893C15.2396 4.38477 15.7465 5.13477 16.1146 5.98893C16.4826 6.8431 16.6667 7.76324 16.6667 8.74935C16.6667 9.79102 16.4965 10.791 16.1563 11.7493C15.816 12.7077 15.3507 13.5966 14.7604 14.416C14.1701 15.2355 13.4688 15.9785 12.6563 16.6452C11.8438 17.3118 10.9583 17.8743 10 18.3327ZM11.6667 15.291C12.6528 14.4577 13.4549 13.482 14.0729 12.3639C14.691 11.2459 15 10.041 15 8.74935C15 7.23546 14.4757 5.95421 13.4271 4.9056C12.3785 3.85699 11.0972 3.33268 9.58333 3.33268C8.06944 3.33268 6.78819 3.85699 5.73958 4.9056C4.69097 5.95421 4.16667 7.23546 4.16667 8.74935C4.16667 10.2632 4.69097 11.5445 5.73958 12.5931C6.78819 13.6417 8.06944 14.166 9.58333 14.166H11.6667V15.291ZM9.5625 13.3118C9.79861 13.3118 10 13.2285 10.1667 13.0618C10.3333 12.8952 10.4167 12.6938 10.4167 12.4577C10.4167 12.2216 10.3333 12.0202 10.1667 11.8535C10 11.6868 9.79861 11.6035 9.5625 11.6035C9.32639 11.6035 9.125 11.6868 8.95833 11.8535C8.79167 12.0202 8.70833 12.2216 8.70833 12.4577C8.70833 12.6938 8.79167 12.8952 8.95833 13.0618C9.125 13.2285 9.32639 13.3118 9.5625 13.3118ZM8.95833 10.666H10.2083C10.2083 10.2493 10.25 9.95768 10.3333 9.79102C10.4167 9.62435 10.6806 9.31879 11.125 8.87435C11.375 8.62435 11.5833 8.35352 11.75 8.06185C11.9167 7.77018 12 7.45768 12 7.12435C12 6.41602 11.7604 5.88477 11.2813 5.5306C10.8021 5.17643 10.2361 4.99935 9.58333 4.99935C8.97222 4.99935 8.45833 5.16949 8.04167 5.50977C7.625 5.85004 7.33333 6.26324 7.16667 6.74935L8.33333 7.20768C8.40278 6.97157 8.53472 6.73893 8.72917 6.50977C8.92361 6.2806 9.20833 6.16602 9.58333 6.16602C9.95833 6.16602 10.2396 6.27018 10.4271 6.47852C10.6146 6.68685 10.7083 6.91602 10.7083 7.16602C10.7083 7.40213 10.6389 7.61393 10.5 7.80143C10.3611 7.98893 10.1944 8.1799 10 8.37435C9.51389 8.79102 9.21875 9.12088 9.11458 9.36393C9.01042 9.60699 8.95833 10.041 8.95833 10.666Z" fill="white"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,5 +0,0 @@
<svg width="111" height="111" viewBox="0 0 111 111" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="110" height="110" rx="20" fill="white"/>
<path d="M68.6778 80.1145V81.6565C68.6778 88.1647 63.4498 93.4567 57.0203 93.4567H29.6574C23.2279 93.4567 17.9999 88.1647 17.9999 81.6565V53.9586C17.9999 47.4503 23.2279 42.1583 29.6574 42.1583H31.1807V80.1218H68.6849L68.6778 80.1145Z" fill="#8E75FA"/>
<path d="M69.1856 70.877H40.2993V38.553C40.2993 27.5202 49.1676 18.5433 60.067 18.5433H69.1927C81.7656 18.5433 91.9999 28.9029 91.9999 41.6298V47.7833C91.9999 60.5102 81.7656 70.8697 69.1927 70.8697L69.1856 70.877ZM53.473 57.5348H69.1856C74.4922 57.5348 78.8119 53.1622 78.8119 47.7905V41.637C78.8119 36.2654 74.4922 31.8928 69.1856 31.8928H60.0598C56.4267 31.8928 53.473 34.8827 53.473 38.5603V57.542V57.5348Z" fill="#571EFA"/>
</svg>

Before

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -97,6 +97,11 @@
--login-logo: url("/static-files/login/logo.svg") no-repeat center; --login-logo: url("/static-files/login/logo.svg") no-repeat center;
} }
/* Speed of flyout mennu */
.flyout-wrapper, .flyout-wrapper--isVisible {
transition: transform .5s cubic-bezier(0,0,.2,1);
}
/* Keycloak user screens begin */ /* Keycloak user screens begin */
#kc-login, #kc-login,
#kc-logout, #kc-logout,
@@ -492,4 +497,174 @@ textarea {
overflow: hidden; overflow: hidden;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
border: 0; border: 0;
}
/* openDesk customization for nubus-frontend below */
.portal-quick-draft {
background-color: var(--color-accent);
color: #fff;
border: 1px solid #d3d7de;
}
.portal-quick-draft__img {
filter: grayscale(1) invert(1);
}
.portal-quick-draft:hover,
.portal-quick-draft__toggle:hover {
background-color: #4519c2;
}
.portal-quick-draft:focus-within {
box-shadow: 0px 0px 0px 3px #c8b9fd;
}
.portal-quick-draft--open:focus-within {
box-shadow: unset;
}
.portal-quick-draft__toggle:focus {
border-color: var(--color-focus);
}
.portal-quick-draft--open,
.portal-quick-draft--open:hover,
.portal-quick-draft--open .portal-quick-draft__toggle:hover {
background-color: #341291;
}
.portal-quick-draft__item {
color: #fff;
}
.portal-quick-draft__item:hover,
.portal-quick-draft__item:focus-visible {
color: hsla(0,0%,100%,.7);
}
.portal-category__title {
margin-bottom: calc(var(--layout-spacing-unit) * 2);
font-size: var(--font-size-3);
font-weight: 700;
}
.portal-category .portal-category__tiles {
--app-tile-side-length: 5.5rem;
--border-radius-apptile: var(--layout-spacing-unit);
grid-gap: calc(var(--layout-spacing-unit) * 2.5) calc(var(--layout-spacing-unit) * 4.5);
}
.portal-tile__box {
box-shadow: none;
border: 1px solid #d9d9d9;
margin-bottom: calc(var(--layout-spacing-unit) * 1);
}
.portal-tile__box--with-scaling-hover:hover {
scale: 1;
}
.portal-tile:hover .portal-tile__box {
border-color: #99a1b2;
}
.portal-tile:focus .portal-tile__box {
border-color: #99a1b2;
box-shadow: 0 0 0 3px #c8b9fd;
}
.portal-corner__inner {
background-color: #203257;
}
.portal-corner__link {
color: #fff;
}
.portal-corner__link:focus-visible,
.portal-corner__link:hover {
color: hsla(0, 0%, 100%, .7);
outline: none;
outline-offset: none;
}
.portal-corner__item:after {
color: hsla(0,0%,100%,.5);
}
.newsfeed-meta__btn {
border: 1px solid var(--bgc-announcements-info);
color: var(--color-accent);
background-color: var(--color-opendesk-white);
}
.newsfeed-meta__btn:focus,
.newsfeed-meta__btn:hover {
border-color: var(--newsfeed-link-hover-color);
}
#header-button-menu {
width: auto;
}
.portal-header__right .header-button[data-test=searchbutton] {
display: none;
}
.portal-sidebar__flyout {
border-radius: 0;
}
.portal-sidenavigation__login-header {
order: 1;
}
.portal-sidenavigation__login-header + .divider {
display: none;
}
.portal-sidenavigation__user-row {
display: block;
height: auto;
}
.portal-sidenavigation__user-text-content {
display: block;
padding: 0;
}
.portal-sidenavigation--username {
display: none;
}
.portal-sidenavigation__logout-link {
padding: 1em 0 1em 20px;
cursor: pointer;
height: auto;
width: 100%;
text-align: left;
font-size: var(--font-size-4);
color: var(--font-color-contrast-high);
font-weight: 600;
text-transform: uppercase;
background-color: transparent;
border: none;
margin: 0;
scale: 1;
display: block;
border-radius: 0;
}
.portal-sidenavigation__logout-link:hover {
background-color: #f5f5f5;
transition: all var(--portal-transition-duration);
}
.portal-category__title::before {
display: block;
content: "";
width: 20px;
height: 20px;
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSIgeG1sbnM6dj0iaHR0cHM6Ly92ZWN0YS5pby9uYW5vIj48cGF0aCBkPSJNNS45MzggNC42ODhhMS4yNSAxLjI1IDAgMCAxLS43NzIgMS4xNTUgMS4yNSAxLjI1IDAgMCAxLTEuMzYyLS4yNzEgMS4yNSAxLjI1IDAgMCAxLS4yNzEtMS4zNjIgMS4yNSAxLjI1IDAgMCAxIDEuMTU1LS43NzIgMS4yNSAxLjI1IDAgMCAxIDEuMjUgMS4yNXpNMTAgMy40MzhhMS4yNSAxLjI1IDAgMCAwLTEuMTU1Ljc3MiAxLjI1IDEuMjUgMCAwIDAgLjI3MSAxLjM2MiAxLjI1IDEuMjUgMCAwIDAgMS4zNjIuMjcxIDEuMjUgMS4yNSAwIDAgMCAuNzcyLTEuMTU1QTEuMjUgMS4yNSAwIDAgMCAxMCAzLjQzOHptNS4zMTMgMi41YTEuMjUgMS4yNSAwIDAgMCAxLjE1NS0uNzcyIDEuMjUgMS4yNSAwIDAgMC0uMjcxLTEuMzYyIDEuMjUgMS4yNSAwIDAgMC0xLjM2Mi0uMjcxIDEuMjUgMS4yNSAwIDAgMC0uNzcyIDEuMTU1IDEuMjUgMS4yNSAwIDAgMCAxLjI1IDEuMjV6TTQuNjg4IDguNzVhMS4yNSAxLjI1IDAgMCAwLTEuMTU1Ljc3MiAxLjI1IDEuMjUgMCAwIDAgLjI3MSAxLjM2MiAxLjI1IDEuMjUgMCAwIDAgMS4zNjIuMjcxQTEuMjUgMS4yNSAwIDAgMCA1LjkzOCAxMGExLjI1IDEuMjUgMCAwIDAtMS4yNS0xLjI1em01LjMxMyAwYTEuMjUgMS4yNSAwIDAgMC0xLjE1NS43NzIgMS4yNSAxLjI1IDAgMCAwIC4yNzEgMS4zNjIgMS4yNSAxLjI1IDAgMCAwIDEuMzYyLjI3MUExLjI1IDEuMjUgMCAwIDAgMTEuMjUgMTAgMS4yNSAxLjI1IDAgMCAwIDEwIDguNzV6bTUuMzEzIDBhMS4yNSAxLjI1IDAgMCAwLTEuMTU1Ljc3MiAxLjI1IDEuMjUgMCAwIDAgLjI3MSAxLjM2MiAxLjI1IDEuMjUgMCAwIDAgMS4zNjIuMjcxQTEuMjUgMS4yNSAwIDAgMCAxNi41NjMgMTBhMS4yNSAxLjI1IDAgMCAwLTEuMjUtMS4yNXpNNC42ODggMTQuMDYzYTEuMjUgMS4yNSAwIDAgMC0xLjE1NS43NzIgMS4yNSAxLjI1IDAgMCAwIC4yNzEgMS4zNjIgMS4yNSAxLjI1IDAgMCAwIDEuMzYyLjI3MSAxLjI1IDEuMjUgMCAwIDAgLjc3Mi0xLjE1NSAxLjI1IDEuMjUgMCAwIDAtMS4yNS0xLjI1em01LjMxMyAwYTEuMjUgMS4yNSAwIDAgMC0xLjE1NS43NzIgMS4yNSAxLjI1IDAgMCAwIC4yNzEgMS4zNjIgMS4yNSAxLjI1IDAgMCAwIDEuMzYyLjI3MSAxLjI1IDEuMjUgMCAwIDAgLjc3Mi0xLjE1NSAxLjI1IDEuMjUgMCAwIDAtMS4yNS0xLjI1em01LjMxMyAwYTEuMjUgMS4yNSAwIDAgMC0xLjE1NS43NzIgMS4yNSAxLjI1IDAgMCAwIC4yNzEgMS4zNjIgMS4yNSAxLjI1IDAgMCAwIDEuMzYyLjI3MSAxLjI1IDEuMjUgMCAwIDAgLjc3Mi0xLjE1NSAxLjI1IDEuMjUgMCAwIDAtMS4yNS0xLjI1eiIgZmlsbD0iIzAwMCIvPjwvc3ZnPg==');
} }