refactor(webapp): ds html (#9247)

This commit is contained in:
Ulf Gebhardt 2026-02-19 22:44:50 +01:00 committed by GitHub
parent 4f4f2e4696
commit 5ef4fecf99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
116 changed files with 1916 additions and 1795 deletions

View File

@ -7,6 +7,6 @@ defineStep('I delete the social media link {string}', (link) => {
.should("be.visible")
cy.get('[data-test="confirm-button"]')
.click()
cy.get('.ds-list-item-content > a')
cy.get(`.ds-list-item a[href="${link}"]`)
.should('not.exist')
})

View File

@ -8,6 +8,6 @@ defineStep('I have added the social media link {string}', (link) => {
.type(link)
.get('[data-test="add-save-button"]')
.click()
cy.get('.ds-list-item-content > a')
cy.get('.ds-list-item a')
.contains(link)
})

View File

@ -9,46 +9,37 @@
### Übersicht
```
Phase 0: Analyse ██████████ 100% (8/8 Schritte)
Phase 3: Migration ██████████ 100% (132/132 Buttons) ✅
───────────────────────────────────────────
Phase 3 ABGESCHLOSSEN: M4a ✅, M4b ✅, M4c ✅ — 0 <base-button> verbleibend
Phase 0: Analyse ██████████ 100% (8/8 Schritte) ✅
Phase 3: OsButton ██████████ 100% (133/133 Buttons) ✅
Phase 4: Tier 1 ██████████ 100% (OsButton, OsIcon, OsSpinner, OsCard) ✅
Phase 4: Tier A → HTML ██████████ 100% (10 ds-* Wrapper → Plain HTML) ✅
Phase 4: Tier B → HTML ░░░░░░░░░░ 0% (ds-chip, ds-number, ds-grid, ds-radio)
Phase 4: Tier 2-4 ░░░░░░░░░░ 0% (OsModal, OsInput, OsMenu, OsSelect, OsTable)
```
### Statistiken
| Metrik | Wert |
|--------|------|
| Webapp Komponenten | 139 |
| Styleguide Komponenten | 38 |
| Styleguide Komponenten | 38 (23 in Webapp genutzt) |
| **Gesamt** | **177** |
| Detailiert analysiert | 3 Familien (Button, Modal, Menu) |
| Duplikate gefunden | 5 direkte + 3 Familien |
| Zur Migration priorisiert | 15 Kern-Komponenten |
| ✅ UI-Library | OsButton, OsIcon, OsSpinner, OsCard (4) |
| ✅ → Plain HTML | Section, Placeholder, Tag, List, ListItem, Container, Heading, Text, Space, Flex, FlexItem (11) |
| ⬜ → Plain HTML | Chip, Number, Grid, GridItem, Radio (5) — Tier B |
| ⬜ → UI-Library | Modal, Input, Menu, MenuItem, Select, Table (6) — Tier 2-4 |
| ⬜ Offen | Form (18 Dateien — HTML oder OsForm?) |
| ⬜ Nicht in Webapp | Code, CopyField, FormItem, InputError, InputLabel, Page, PageTitle, Logo, Avatar, TableCol, TableHeadCol (11) |
### OsButton Migration (Phase 3) ✅
| Status | Anzahl | Details |
|--------|--------|---------|
| ✅ Migriert | 132 | 78 Dateien, alle `<base-button>` ersetzt |
| ⬜ Verbleibend | 0 | Nur BaseButton.vue Definition + Test/Snapshot-Dateien |
| **Gesamt** | **132** | **100% erledigt** |
**Alle 132 Buttons migriert in 78 Dateien ✅**
Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-Templates.
**133 Buttons migriert in 79 Dateien ✅** — BaseButton.vue gelöscht, base-components.js Plugin entfernt.
**Erkenntnisse aus der Migration:**
- `type="submit"` muss explizit gesetzt werden (OsButton Default: `type="button"`)
- DsForm `errors` ist ein Objekt → `!!errors` für Boolean-Cast bei `:disabled`
- CSS `.base-button` Selektoren → `> button` oder `button`
- Position/Dimensions brauchen `!important` für Tailwind-Override
- Filter-Buttons nutzen `:appearance="condition ? 'filled' : 'outline'"` Pattern
- Circle-Buttons mit Icon: `<template #icon><base-icon :name="..." /></template>`
**Verbleibende Cleanup-Aufgaben:**
- [ ] Snapshot-Dateien aktualisieren (enthalten noch `base-button` Referenzen)
- [ ] Test-Dateien aktualisieren (Selektoren `.base-button``button` oder `os-button-stub`)
- [ ] BaseButton.vue Komponente ggf. entfernen (wenn nicht mehr referenziert)
- [ ] CSS-Selektor `.base-button` in ImageUploader.vue entfernen
- Circle-Buttons mit Icon: `<template #icon><os-icon :icon="..." /></template>`
---
@ -58,62 +49,62 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
> Live: http://styleguide.ocelot.social/
### Data Display
| # | Komponente | Status | Webapp-Duplikat | Varianten | Priorität | Notizen |
|---|------------|--------|-----------------|-----------|-----------|---------|
| 1 | Avatar | ⬜ Ausstehend | | | | |
| 2 | Card | ⬜ Ausstehend | BaseCard? | | | |
| 3 | Chip | ⬜ Ausstehend | | | | |
| 4 | Code | ⬜ Ausstehend | | | | |
| 5 | Icon | ⬜ Ausstehend | BaseIcon? | | | |
| 6 | Number | ⬜ Ausstehend | | | | |
| 7 | Placeholder | ⬜ Ausstehend | | | | |
| 8 | Spinner | ⬜ Ausstehend | LoadingSpinner? | | | |
| 9 | Table | ⬜ Ausstehend | | | | |
| 10 | TableCol | ⬜ Ausstehend | | | | |
| 11 | TableHeadCol | ⬜ Ausstehend | | | | |
| 12 | Tag | ⬜ Ausstehend | | | | |
| # | Komponente | Status | Notizen |
|---|------------|--------|---------|
| 1 | Avatar | ⬜ Nicht genutzt | Webapp nutzt eigenes ProfileAvatar |
| 2 | Card | ✅ UI-Library | → OsCard (BaseCard gelöscht) |
| 3 | Chip | ⬜ Tier B | 5 Dateien → Plain HTML `<span class="ds-chip">` |
| 4 | Code | ⬜ Nicht genutzt | Nicht in Webapp verwendet |
| 5 | Icon | ✅ UI-Library | → OsIcon (BaseIcon gelöscht, 82 Ocelot-Icons) |
| 6 | Number | ⬜ Tier B | 5 Dateien → Plain HTML `<div class="ds-number">` |
| 7 | Placeholder | ✅ → HTML | Tier A: `<div class="ds-placeholder">` |
| 8 | Spinner | ✅ UI-Library | → OsSpinner (LoadingSpinner gelöscht) |
| 9 | Table | ⬜ Tier 4 | 7 Dateien → OsTable |
| 10 | TableCol | ⬜ Tier 4 | Intern von Table genutzt |
| 11 | TableHeadCol | ⬜ Tier 4 | Intern von Table genutzt |
| 12 | Tag | ✅ → HTML | Tier A: `<span class="ds-tag">` |
### Data Input
| # | Komponente | Status | Webapp-Duplikat | Varianten | Priorität | Notizen |
|---|------------|--------|-----------------|-----------|-----------|---------|
| 13 | Button | ⏳ Migration | BaseButton, CustomButton, ActionButton, ... | | | → OsButton (41/90 migriert) |
| 14 | CopyField | ⬜ Ausstehend | | | | |
| 15 | Form | ⬜ Ausstehend | | | | |
| 16 | FormItem | ⬜ Ausstehend | | | | |
| 17 | Input | ⬜ Ausstehend | SearchableInput, LinkInput | | | |
| 18 | InputError | ⬜ Ausstehend | | | | |
| 19 | InputLabel | ⬜ Ausstehend | | | | |
| 20 | Radio | ⬜ Ausstehend | | | | |
| 21 | Select | ⬜ Ausstehend | Dropdown, LocationSelect | | | |
| # | Komponente | Status | Notizen |
|---|------------|--------|---------|
| 13 | Button | ✅ UI-Library | → OsButton (133 Buttons in 79 Dateien, BaseButton gelöscht) |
| 14 | CopyField | ⬜ Nicht genutzt | Nicht in Webapp verwendet |
| 15 | Form | ⬜ Offen | 18 Dateien — HTML `<form>` oder OsForm? |
| 16 | FormItem | ⬜ Nicht genutzt | Nicht in Webapp verwendet |
| 17 | Input | ⬜ Tier 2 | 23 Dateien → OsInput (gekoppelt mit Form) |
| 18 | InputError | ⬜ Nicht genutzt | Intern von Input genutzt |
| 19 | InputLabel | ⬜ Nicht genutzt | Intern von Input genutzt |
| 20 | Radio | ⬜ Tier B | 1 Datei → native `<input type="radio">` |
| 21 | Select | ⬜ Tier 4 | 3 Dateien → OsSelect |
### Layout
| # | Komponente | Status | Webapp-Duplikat | Varianten | Priorität | Notizen |
|---|------------|--------|-----------------|-----------|-----------|---------|
| 22 | Container | ⬜ Ausstehend | | | | |
| 23 | Flex | ⬜ Ausstehend | | | | |
| 24 | FlexItem | ⬜ Ausstehend | | | | |
| 25 | Grid | ⬜ Ausstehend | MasonryGrid? | | | |
| 26 | GridItem | ⬜ Ausstehend | MasonryGridItem? | | | |
| 27 | Modal | ⬜ Ausstehend | Modal, ConfirmModal, ... | | | |
| 28 | Page | ⬜ Ausstehend | InternalPage? | | | |
| 29 | PageTitle | ⬜ Ausstehend | | | | |
| 30 | Section | ⬜ Ausstehend | | | | |
| 31 | Space | ⬜ Ausstehend | | | | |
| # | Komponente | Status | Notizen |
|---|------------|--------|---------|
| 22 | Container | ✅ → HTML | Tier A: `<div class="ds-container ds-container-{width}">` |
| 23 | Flex | ✅ → HTML | Tier A: Plain HTML + CSS @media Queries |
| 24 | FlexItem | ✅ → HTML | Tier A: Plain HTML + CSS @media Queries |
| 25 | Grid | ⬜ Tier B | 2 Dateien → CSS Grid |
| 26 | GridItem | ⬜ Tier B | 8 Dateien → CSS Grid |
| 27 | Modal | ⬜ Tier 2 | 7 Dateien → OsModal |
| 28 | Page | ⬜ Nicht genutzt | Nicht direkt in Webapp verwendet |
| 29 | PageTitle | ⬜ Nicht genutzt | Nicht direkt in Webapp verwendet |
| 30 | Section | ✅ → HTML | Tier A: `<section class="ds-section">` |
| 31 | Space | ✅ → HTML | Tier A: `<div class="ds-mb-{size}">` / `<div class="ds-my-{size}">` |
### Navigation
| # | Komponente | Status | Webapp-Duplikat | Varianten | Priorität | Notizen |
|---|------------|--------|-----------------|-----------|-----------|---------|
| 32 | List | ⬜ Ausstehend | | | | |
| 33 | ListItem | ⬜ Ausstehend | | | | |
| 34 | Logo | ⬜ Ausstehend | Logo | | | DUPLIKAT |
| 35 | Menu | ⬜ Ausstehend | HeaderMenu, ContentMenu, ... | | | |
| 36 | MenuItem | ⬜ Ausstehend | | | | |
| # | Komponente | Status | Notizen |
|---|------------|--------|---------|
| 32 | List | ✅ → HTML | Tier A: `<ul class="ds-list">` |
| 33 | ListItem | ✅ → HTML | Tier A: `<li class="ds-list-item">` |
| 34 | Logo | ⬜ Nicht genutzt | Webapp nutzt eigenes Logo |
| 35 | Menu | ⬜ Tier 3 | 11 Dateien → OsMenu |
| 36 | MenuItem | ⬜ Tier 3 | 6 Dateien → OsMenuItem |
### Typography
| # | Komponente | Status | Webapp-Duplikat | Varianten | Priorität | Notizen |
|---|------------|--------|-----------------|-----------|-----------|---------|
| 37 | Heading | ⬜ Ausstehend | SearchHeading? | | | |
| 38 | Text | ⬜ Ausstehend | | | | |
| # | Komponente | Status | Notizen |
|---|------------|--------|---------|
| 37 | Heading | ✅ → HTML | Tier A: `<h1-h4 class="ds-heading ds-heading-h{n}">` |
| 38 | Text | ✅ → HTML | Tier A: `<p class="ds-text ds-text-{color}">` |
---
@ -132,7 +123,7 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
### A-B
| # | Komponente | Status | Kategorie | Styleguide-Pendant | Notizen |
|---|------------|--------|-----------|-------------------|---------|
| 1 | ActionButton | ⬜ Ausstehend | Button | Button | 🔄 Button-Familie |
| 1 | ActionButton | ✅ Migriert | Button | Button | 🔄 Button-Familie, nutzt OsButton |
| 2 | ActionRadiusSelect | ⬜ Ausstehend | Input | | |
| 3 | AddChatRoomByUserSearch | ⬜ Ausstehend | Feature | | Chat-spezifisch |
| 4 | AddGroupMember | ⬜ Ausstehend | Feature | | Group-spezifisch |
@ -141,21 +132,21 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
| 7 | BadgeSelection | ⬜ Ausstehend | Input | | |
| 8 | Badges | ⬜ Ausstehend | Display | | |
| 9 | BadgesSection | ⬜ Ausstehend | Display | | |
| 10 | BaseButton | ⏳ Migration | Button | Button | 🔄 → OsButton (41/90 migriert) |
| 11 | BaseCard | ⬜ Ausstehend | Layout | Card | 🔗 DUPLIKAT |
| 12 | BaseIcon | ⬜ Ausstehend | Display | Icon | 🔗 DUPLIKAT |
| 10 | ~~BaseButton~~ | ✅ Gelöscht | Button | Button | → OsButton (133 Buttons, Komponente gelöscht) |
| 11 | ~~BaseCard~~ | ✅ Gelöscht | Layout | Card | → OsCard (~30 Dateien, Komponente gelöscht) |
| 12 | ~~BaseIcon~~ | ✅ Gelöscht | Display | Icon | → OsIcon (131 Nutzungen, Komponente gelöscht) |
### C
| # | Komponente | Status | Kategorie | Styleguide-Pendant | Notizen |
|---|------------|--------|-----------|-------------------|---------|
| 13 | CategoriesFilter | ⬜ Ausstehend | Filter | | |
| 14 | CategoriesMenu | ⬜ Ausstehend | Navigation | Menu | |
| 15 | CategoriesSelect | ⏳ Teilweise | Input | Select | Buttons → OsButton (icon) |
| 15 | CategoriesSelect | ✅ Migriert | Input | Select | Buttons → OsButton (icon) |
| 16 | ChangePassword | ⬜ Ausstehend | Feature | | Auth-spezifisch |
| 17 | Change | ⬜ Ausstehend | Feature | | |
| 18 | Chat | ⬜ Ausstehend | Feature | | Chat-spezifisch |
| 19 | ChatNotificationMenu | ⬜ Ausstehend | Feature | | Chat-spezifisch |
| 20 | CommentCard | ⏳ Teilweise | Display | Card | 1/2 Buttons → OsButton |
| 20 | CommentCard | ✅ Migriert | Display | Card | Buttons → OsButton, BaseCard → OsCard |
| 21 | CommentForm | ⬜ Ausstehend | Input | Form | |
| 22 | CommentList | ⬜ Ausstehend | Display | List | |
| 23 | ComponentSlider | ⬜ Ausstehend | Layout | | |
@ -163,31 +154,31 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
| 25 | ContentMenu | ⬜ Ausstehend | Navigation | Menu | |
| 26 | ContentViewer | ⬜ Ausstehend | Display | | |
| 27 | ContextMenu | ⬜ Ausstehend | Navigation | Menu | |
| 28 | ContributionForm | ⏳ Teilweise | Feature | Form | Cancel → OsButton |
| 28 | ContributionForm | ✅ Migriert | Feature | Form | Buttons → OsButton, ds-* → HTML |
| 29 | CounterIcon | ⬜ Ausstehend | Display | Icon | |
| 30 | CountTo | ⬜ Ausstehend | Display | Number | Animation |
| 31 | CreateInvitation | ⬜ Ausstehend | Feature | | |
| 32 | CtaJoinLeaveGroup | ⬜ Ausstehend | Button | Button | 🔄 Button-Familie |
| 33 | CtaUnblockAuthor | ✅ Migriert | Button | Button | Button → OsButton (icon) |
| 34 | CustomButton | ⬜ Ausstehend | Button | Button | 🔄 Button-Familie |
| 32 | CtaJoinLeaveGroup | ✅ Migriert | Button | Button | 🔄 Button-Familie, nutzt OsButton |
| 33 | CtaUnblockAuthor | ✅ Migriert | Button | Button | Nutzt OsButton (icon, as="nuxt-link") |
| 34 | CustomButton | ✅ Migriert | Button | Button | 🔄 Button-Familie, nutzt OsButton |
### D-E
| # | Komponente | Status | Kategorie | Styleguide-Pendant | Notizen |
|---|------------|--------|-----------|-------------------|---------|
| 35 | DateTimeRange | ⬜ Ausstehend | Input | | |
| 36 | DeleteData | ⬜ Ausstehend | Feature | | |
| 37 | DeleteUserModal | ⏳ Teilweise | Feedback | Modal | 🔄 Modal-Familie, Buttons → OsButton |
| 38 | DisableModal | ⏳ Teilweise | Feedback | Modal | 🔄 Modal-Familie, Buttons → OsButton |
| 37 | DeleteUserModal | ✅ Migriert | Feedback | Modal | 🔄 Modal-Familie, Buttons → OsButton |
| 38 | DisableModal | ✅ Migriert | Feedback | Modal | 🔄 Modal-Familie, Buttons → OsButton |
| 39 | DonationInfo | ✅ Migriert | Display | | Button → OsButton |
| 40 | Dropdown | ⬜ Ausstehend | Input | Select | |
| 41 | DropdownFilter | ⬜ Ausstehend | Filter | Select | |
| 42 | Editor | ⬜ Ausstehend | Input | | Rich-Text |
| 43 | EmailDisplayAndVerify | ⬜ Ausstehend | Feature | | |
| 44 | EmbedComponent | ⏳ Teilweise | Display | | 2/3 Buttons → OsButton |
| 45 | EmotionButton | ⬜ Ausstehend | Button | Button | |
| 44 | EmbedComponent | ✅ Migriert | Display | | Buttons → OsButton |
| 45 | EmotionButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 46 | Emotions | ⬜ Ausstehend | Feature | | |
| 47 | Empty | ⬜ Ausstehend | Feedback | Placeholder | |
| 48 | EnterNonce | ⏳ Teilweise | Feature | | Auth, Submit → OsButton |
| 48 | EnterNonce | ✅ Migriert | Feature | | Auth, Submit → OsButton |
### F-G
| # | Komponente | Status | Kategorie | Styleguide-Pendant | Notizen |
@ -197,12 +188,12 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
| 51 | FilterMenu | ⬜ Ausstehend | Navigation | Menu | |
| 52 | FilterMenuComponent | ⬜ Ausstehend | Navigation | Menu | |
| 53 | FilterMenuSection | ⬜ Ausstehend | Navigation | Menu | |
| 54 | FollowButton | ⬜ Ausstehend | Button | Button | |
| 54 | FollowButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 55 | FollowingFilter | ⬜ Ausstehend | Filter | | |
| 56 | FollowList | ⬜ Ausstehend | Display | List | |
| 57 | GroupButton | ⬜ Ausstehend | Button | Button | |
| 57 | GroupButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 58 | GroupContentMenu | ⬜ Ausstehend | Navigation | Menu | |
| 59 | GroupForm | ⏳ Teilweise | Input | Form | 1/2 Buttons → OsButton |
| 59 | GroupForm | ✅ Migriert | Input | Form | Buttons → OsButton |
| 60 | GroupLink | ⬜ Ausstehend | Navigation | | |
| 61 | GroupList | ⬜ Ausstehend | Display | List | |
| 62 | GroupMember | ✅ Migriert | Display | | Button → OsButton |
@ -213,41 +204,41 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
|---|------------|--------|-----------|-------------------|---------|
| 64 | Hashtag | ⬜ Ausstehend | Display | Tag/Chip | |
| 65 | HashtagsFilter | ⬜ Ausstehend | Filter | | |
| 66 | HeaderButton | ⬜ Ausstehend | Button | Button | 🔄 Button-Familie |
| 66 | HeaderButton | ✅ Migriert | Button | Button | 🔄 Button-Familie, nutzt OsButton |
| 67 | HeaderMenu | ⬜ Ausstehend | Navigation | Menu | |
| 68 | ImageUploader | ⏳ Teilweise | Input | | Crop-Buttons → OsButton |
| 68 | ImageUploader | ✅ Migriert | Input | | Crop-Buttons → OsButton, Spinner → OsSpinner |
| 69 | index | ⬜ Ausstehend | ? | | Prüfen |
| 70 | InternalPage | ⬜ Ausstehend | Layout | Page | |
| 71 | Invitation | ⬜ Ausstehend | Feature | | |
| 72 | InvitationList | ⬜ Ausstehend | Display | List | |
| 73 | InviteButton | ⬜ Ausstehend | Button | Button | |
| 74 | JoinLeaveButton | ⬜ Ausstehend | Button | Button | |
| 75 | LabeledButton | ⬜ Ausstehend | Button | Button | 🔄 Button-Familie |
| 73 | InviteButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 74 | JoinLeaveButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 75 | LabeledButton | ✅ Migriert | Button | Button | 🔄 Button-Familie, nutzt OsButton |
| 76 | LinkInput | ⬜ Ausstehend | Input | Input | |
| 77 | LoadingSpinner | ⬜ Ausstehend | Feedback | Spinner | 🔗 DUPLIKAT |
| 77 | ~~LoadingSpinner~~ | ✅ Gelöscht | Feedback | Spinner | → OsSpinner (Komponente gelöscht) |
| 78 | LocaleSwitch | ⬜ Ausstehend | Navigation | | |
| 79 | LocationInfo | ⬜ Ausstehend | Display | | |
| 80 | LocationSelect | ⏳ Teilweise | Input | Select | Close-Button → OsButton (icon) |
| 80 | LocationSelect | ✅ Migriert | Input | Select | Close-Button → OsButton (icon) |
| 81 | LocationTeaser | ⬜ Ausstehend | Display | Card | |
| 82 | LoginButton | ⬜ Ausstehend | Button | Button | |
| 82 | LoginButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 83 | LoginForm | ⬜ Ausstehend | Feature | Form | Auth |
| 84 | Logo | ⬜ Ausstehend | Display | Logo | 🔗 DUPLIKAT |
| 84 | Logo | ⬜ Ausstehend | Display | Logo | 🔗 DUPLIKAT (noch ungelöst) |
### M-O
| # | Komponente | Status | Kategorie | Styleguide-Pendant | Notizen |
|---|------------|--------|-----------|-------------------|---------|
| 85 | MapButton | ⬜ Ausstehend | Button | Button | |
| 85 | MapButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 86 | MapStylesButtons | ✅ Migriert | Button | Button | Button → OsButton |
| 87 | MasonryGrid | ⬜ Ausstehend | Layout | Grid | |
| 88 | MasonryGridItem | ⬜ Ausstehend | Layout | GridItem | |
| 89 | MenuBar | ⬜ Ausstehend | Navigation | Menu | |
| 90 | MenuBarButton | ⬜ Ausstehend | Button | Button | 🔄 Button-Familie |
| 90 | MenuBarButton | ✅ Migriert | Button | Button | 🔄 Button-Familie, nutzt OsButton |
| 91 | MenuLegend | ⬜ Ausstehend | Navigation | | |
| 92 | Modal | ⬜ Ausstehend | Feedback | Modal | 🔗 DUPLIKAT |
| 93 | MySomethingList | ⏳ Teilweise | Display | List | Cancel → OsButton |
| 94 | NotificationMenu | ⏳ Teilweise | Navigation | Menu | 2/3 Buttons → OsButton |
| 93 | MySomethingList | ✅ Migriert | Display | List | Buttons → OsButton |
| 94 | NotificationMenu | ✅ Migriert | Navigation | Menu | Buttons → OsButton |
| 95 | NotificationsTable | ⬜ Ausstehend | Display | Table | |
| 96 | ObserveButton | ⬜ Ausstehend | Button | Button | |
| 96 | ObserveButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 97 | OrderByFilter | ⬜ Ausstehend | Filter | | |
### P-R
@ -267,10 +258,10 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
| 109 | RegistrationSlideNonce | ⬜ Ausstehend | Feature | | Auth |
| 110 | RegistrationSlideNoPublic | ⬜ Ausstehend | Feature | | Auth |
| 111 | RegistrationSlider | ⬜ Ausstehend | Feature | | Auth |
| 112 | ReleaseModal | ⏳ Teilweise | Feedback | Modal | 🔄 Modal-Familie, Cancel → OsButton |
| 112 | ReleaseModal | ✅ Migriert | Feedback | Modal | 🔄 Modal-Familie, Buttons → OsButton |
| 113 | ReportList | ⬜ Ausstehend | Display | List | |
| 114 | ReportModal | ⬜ Ausstehend | Feedback | Modal | 🔄 Modal-Familie |
| 115 | ReportRow | ⏳ Teilweise | Display | | More Details → OsButton |
| 115 | ReportRow | ✅ Migriert | Display | | More Details → OsButton |
| 116 | ReportsTable | ⬜ Ausstehend | Display | Table | |
| 117 | Request | ⬜ Ausstehend | Feature | | |
| 118 | ResponsiveImage | ⬜ Ausstehend | Display | | |
@ -285,7 +276,7 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
| 123 | SearchPost | ⬜ Ausstehend | Feature | | Search |
| 124 | SearchResults | ⬜ Ausstehend | Feature | | Search |
| 125 | SelectUserSearch | ⬜ Ausstehend | Input | Select | |
| 126 | ShoutButton | ⬜ Ausstehend | Button | Button | |
| 126 | ShoutButton | ✅ Migriert | Button | Button | Nutzt OsButton intern |
| 127 | ShowPassword | ⬜ Ausstehend | Input | | |
| 128 | Signup | ⬜ Ausstehend | Feature | | Auth |
| 129 | SocialMedia | ⬜ Ausstehend | Display | | |
@ -307,36 +298,35 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
## Identifizierte Duplikate & Konsolidierung
### Direkte Duplikate (Webapp ↔ Styleguide)
| Webapp | Styleguide | Aktion |
|--------|------------|--------|
| Logo | Logo | Konsolidieren zu OsLogo |
| Modal | Modal | Konsolidieren zu OsModal |
| BaseCard | Card | Konsolidieren zu OsCard |
| BaseIcon | Icon | Konsolidieren zu OsIcon |
| LoadingSpinner | Spinner | Konsolidieren zu OsSpinner |
| Webapp | Styleguide | Aktion | Status |
|--------|------------|--------|--------|
| Logo | Logo | Konsolidieren zu OsLogo | ⬜ Ausstehend |
| Modal | Modal | Konsolidieren zu OsModal | ⬜ Ausstehend |
| ~~BaseCard~~ | Card | → OsCard | ✅ Erledigt (BaseCard gelöscht) |
| ~~BaseIcon~~ | Icon | → OsIcon | ✅ Erledigt (BaseIcon gelöscht) |
| ~~LoadingSpinner~~ | Spinner | → OsSpinner | ✅ Erledigt (LoadingSpinner gelöscht) |
### Button-Familie (zur Konsolidierung)
| Komponente | Beschreibung | Ziel |
|------------|--------------|------|
| Button (Styleguide) | Basis-Button | OsButton |
| BaseButton | Basis-Button | → OsButton |
| CustomButton | Angepasster Button | → OsButton variant |
| ActionButton | Aktions-Button | → OsButton variant |
| HeaderButton | Header-Button | → OsButton variant |
| LabeledButton | Button mit Label | → OsButton + Label |
| MenuBarButton | Menü-Button | → OsButton variant |
| FollowButton | Follow-Aktion | Feature-spezifisch |
| GroupButton | Gruppen-Aktion | Feature-spezifisch |
| InviteButton | Einladen | Feature-spezifisch |
| LoginButton | Login | Feature-spezifisch |
| ShoutButton | Shout-Aktion | Feature-spezifisch |
| ObserveButton | Beobachten | Feature-spezifisch |
| EmotionButton | Emotion | Feature-spezifisch |
| JoinLeaveButton | Beitreten/Verlassen | Feature-spezifisch |
| MapButton | Karten-Button | Feature-spezifisch |
| MapStylesButtons | Kartenstile | ✅ → OsButton |
| CtaJoinLeaveGroup | CTA | Feature-spezifisch |
| CtaUnblockAuthor | CTA | Feature-spezifisch |
### Button-Familie ✅ (alle nutzen OsButton)
| Komponente | Status | Notizen |
|------------|--------|---------|
| ~~Button (Styleguide)~~ | ✅ Ersetzt | → OsButton |
| ~~BaseButton~~ | ✅ Gelöscht | → OsButton (133 Buttons) |
| CustomButton | ✅ Nutzt OsButton | Feature-Wrapper |
| ActionButton | ✅ Nutzt OsButton | Feature-Wrapper |
| HeaderButton | ✅ Nutzt OsButton | Feature-Wrapper |
| LabeledButton | ✅ Nutzt OsButton | Feature-Wrapper |
| MenuBarButton | ✅ Nutzt OsButton | Feature-Wrapper |
| FollowButton | ✅ Nutzt OsButton | Feature-spezifisch |
| GroupButton | ✅ Nutzt OsButton | Feature-spezifisch |
| InviteButton | ✅ Nutzt OsButton | Feature-spezifisch |
| LoginButton | ✅ Nutzt OsButton | Feature-spezifisch |
| EmotionButton | ✅ Nutzt OsButton | Feature-spezifisch |
| JoinLeaveButton | ✅ Nutzt OsButton | Feature-spezifisch |
| MapButton | ✅ Nutzt OsButton | Feature-spezifisch |
| MapStylesButtons | ✅ Nutzt OsButton | Feature-spezifisch |
| PaginationButtons | ✅ Nutzt OsButton | Feature-spezifisch |
| CtaJoinLeaveGroup | ✅ Nutzt OsButton | Feature-spezifisch |
| CtaUnblockAuthor | ✅ Nutzt OsButton | Feature-spezifisch |
### Modal-Familie (zur Konsolidierung)
| Komponente | Beschreibung | Ziel |
@ -366,24 +356,26 @@ Migration vollständig abgeschlossen. 0 `<base-button>` Tags verbleiben in Vue-T
## Kategorisierung
### Basis-Komponenten (hohe Priorität)
Diese sollten zuerst migriert werden:
- Button → OsButton
- Card → OsCard
- Icon → OsIcon
### Basis-Komponenten — UI-Library ✅
- ~~Button → OsButton~~
- ~~Card → OsCard~~
- ~~Icon → OsIcon~~
- ~~Spinner → OsSpinner~~
### Basis-Komponenten — UI-Library (ausstehend)
- Modal → OsModal
- Input → OsInput
- Select → OsSelect
- Avatar → OsAvatar
- Spinner → OsSpinner
- Avatar → OsAvatar (falls benötigt)
### Layout-Komponenten
- Container, Flex, Grid, Page, Section, Space
### Layout & Typography — → Plain HTML ✅ (Tier A)
- ~~Container, Flex, FlexItem, Section, Space~~ ✅ → HTML + CSS
- ~~Heading, Text, List, ListItem, Tag, Placeholder~~ ✅ → HTML + CSS
### Typography
- Heading, Text
### Noch zu migrieren (Tier B → Plain HTML)
- Chip, Number, Grid, GridItem, Radio
### Feature-Komponenten (niedrigere Priorität)
### Feature-Komponenten (bleiben in Webapp)
- Chat, Group, Registration, Search, etc.
---
@ -409,6 +401,9 @@ Diese sollten zuerst migriert werden:
| 2026-02-09 | Claude | **Milestone 4a abgeschlossen** | 6 weitere: donations, profile (2x), badges, notifications/index, ReportRow |
| 2026-02-11 | Claude | **M4b: icon + circle** | icon-Slot implementiert, circle-Prop mit CVA |
| 2026-02-11 | Claude | **9 icon-Buttons migriert (M4c)** | DisableModal, DeleteUserModal, CtaUnblockAuthor, LocationSelect, CategoriesSelect, my-email-address, profile Chat, PaginationButtons (2x circle) |
| 2026-02-11→18 | Claude | **Sessions 12-26** | OsButton M4c abgeschlossen, OsIcon, OsSpinner, OsCard implementiert + Webapp-Migration, BaseButton/BaseCard/BaseIcon/LoadingSpinner gelöscht |
| 2026-02-19 | Claude | **Tier A Migration** | 10 ds-* Vue-Wrapper → Plain HTML + CSS, _ds-compat.scss, ~450 Nutzungen in ~90 Dateien |
| 2026-02-19 | Claude | **Katalog konsolidiert** | Styleguide- und Webapp-Tabellen aktualisiert, veraltete Status korrigiert |
---
@ -417,40 +412,40 @@ Diese sollten zuerst migriert werden:
### Phase 0: Analyse ✅
1. [x] Webapp-Komponenten auflisten
2. [x] Styleguide-Komponenten auflisten
3. [x] Offensichtliche Duplikate identifizieren
4. [x] Button-Familie im Detail analysieren
5. [x] Modal-Familie im Detail analysieren
6. [x] Menu-Familie im Detail analysieren
7. [x] Priorisierung festlegen
8. [x] Konsolidierungsplan finalisieren
3. [x] Duplikate und Familien identifizieren
4. [x] Button/Modal/Menu im Detail analysieren
5. [x] Priorisierung und Konsolidierungsplan
### Phase 3: OsButton Migration (in Arbeit)
9. [x] OsButton entwickeln (CVA, vue-demi)
10. [x] Webapp-Integration (Jest, Docker, CI)
11. [x] 16 Buttons migrieren (validiert ✅)
### Phase 3: OsButton Migration ✅
6. [x] OsButton entwickeln (CVA, vue-demi)
7. [x] 133 Buttons in 79 Dateien migriert
8. [x] BaseButton.vue gelöscht, base-components.js Plugin entfernt
**Milestone 4a: 14 Buttons ohne neue Props** ✅
12. [x] Modal Cancel-Buttons (3)
13. [x] Form Cancel/Submit-Buttons (3)
14. [x] ImageUploader Crop-Buttons (2)
15. [x] Page Buttons (6)
### Phase 4: Tier 1 — UI-Library Kern ✅
9. [x] OsIcon + 82 Ocelot-Icons, BaseIcon gelöscht
10. [x] OsSpinner + Webapp-Migration, LoadingSpinner gelöscht
11. [x] OsCard + Webapp-Migration, BaseCard gelöscht
**Milestone 4b: Props für ~49 Buttons hinzufügen**
16. [x] icon-Slot zu OsButton hinzufügen ✅
17. [x] circle-Variant zu OsButton hinzufügen ✅
18. [ ] loading-Prop zu OsButton hinzufügen
### Phase 4: Tier A — ds-* → Plain HTML ✅
12. [x] _ds-compat.scss Utility-Klassen
13. [x] 10 ds-* Wrapper → HTML + CSS (~450 Nutzungen, ~90 Dateien)
**Milestone 4c: ~49 Buttons mit neuen Props migrieren**
19. [ ] Button-Komponenten (~15)
20. [ ] Navigation (~8)
21. [ ] Editor (~15)
22. [ ] Filter/Chat (~10)
23. [ ] Forms/Modals (~5)
24. [ ] Features/Pages (~12)
### Phase 4: Tier B — ds-* → Plain HTML (ausstehend)
14. [ ] ds-chip (5 Dateien) → `<span class="ds-chip">`
15. [ ] ds-number (5 Dateien) → `<div class="ds-number">`
16. [ ] ds-grid / ds-grid-item (10 Dateien) → CSS Grid
17. [ ] ds-radio (1 Datei) → native `<input type="radio">`
### Phase 4: Tier 2-4 — UI-Library (ausstehend)
18. [ ] OsModal (7 Dateien)
19. [ ] OsInput (23 Dateien, gekoppelt mit ds-form)
20. [ ] OsMenu / OsMenuItem (17 Dateien)
21. [ ] OsSelect (3 Dateien), OsTable (7 Dateien)
22. [ ] ds-form → HTML `<form>` oder OsForm (18 Dateien)
---
**✅ Phase 0 abgeschlossen!** Phase 3 zu 27% erledigt (24/90 Buttons migriert). Milestone 4a: 8/14 Buttons.
**✅ Phase 0-3 abgeschlossen. Phase 4: Tier 1 + Tier A ✅, Tier B + Tier 2-4 ausstehend.**
---
@ -544,66 +539,47 @@ Diese sollten zuerst migriert werden:
---
### Feature-Buttons (Business-Logik)
### Feature-Buttons (Business-Logik)
Diese Buttons enthalten Business-Logik und sollten **nicht** in OsButton konsolidiert werden:
Feature-Buttons behalten Business-Logik, nutzen aber intern alle OsButton:
| Komponente | Beschreibung | Migration |
|------------|--------------|-----------|
| FollowButton | Folgen/Entfolgen Logik | Bleibt Feature-Komponente |
| GroupButton | Gruppen-Aktionen | Bleibt Feature-Komponente |
| InviteButton | Einladungs-Logik | Bleibt Feature-Komponente |
| LoginButton | Auth-Logik | Bleibt Feature-Komponente |
| ShoutButton | Shout-Logik | Bleibt Feature-Komponente |
| ObserveButton | Beobachten-Logik | Bleibt Feature-Komponente |
| EmotionButton | Reaktions-Logik | Bleibt Feature-Komponente |
| JoinLeaveButton | Gruppen Beitreten/Verlassen | Bleibt Feature-Komponente |
| MapButton | Karten-Toggle | Bleibt Feature-Komponente |
| MapStylesButtons | Kartenstil-Auswahl | Bleibt Feature-Komponente |
| PaginationButtons | Seitennavigation | Bleibt Feature-Komponente |
| Komponente | Status |
|------------|--------|
| FollowButton | ✅ Nutzt OsButton |
| GroupButton | ✅ Nutzt OsButton |
| InviteButton | ✅ Nutzt OsButton |
| LoginButton | ✅ Nutzt OsButton |
| ShoutButton | ✅ Nutzt OsButton |
| ObserveButton | ✅ Nutzt OsButton |
| EmotionButton | ✅ Nutzt OsButton |
| JoinLeaveButton | ✅ Nutzt OsButton |
| MapButton | ✅ Nutzt OsButton |
| MapStylesButtons | ✅ Nutzt OsButton |
| PaginationButtons | ✅ Nutzt OsButton |
---
### Konsolidierungsvorschlag: OsButton
### Konsolidierungsvorschlag: OsButton ✅ IMPLEMENTIERT
> **Hinweis:** Die tatsächliche API weicht vom ursprünglichen Vorschlag ab.
> Siehe `packages/ui/src/components/OsButton/OsButton.vue` für die aktuelle Implementierung.
**Implementierte API (CVA-basiert):**
```typescript
interface OsButtonProps {
// Variante
variant?: 'default' | 'primary' | 'secondary' | 'danger'
// Stil
filled?: boolean // Gefüllter Hintergrund (default: false = outline)
ghost?: boolean // Komplett transparent
// Größe
size?: 'tiny' | 'small' | 'base' | 'large'
// Form
circle?: boolean // Runder Button
fullWidth?: boolean // Volle Breite
// Icon
icon?: string
iconPosition?: 'left' | 'right'
// Zustände
variant?: 'default' | 'primary' | 'secondary' | 'danger' | 'warning' | 'success' | 'info'
appearance?: 'filled' | 'outline' | 'ghost' // statt separate booleans
size?: 'sm' | 'md' | 'lg' | 'xl' // vereinfachte Größen
circle?: boolean
fullWidth?: boolean
loading?: boolean
disabled?: boolean
// Link-Support
to?: string | RouteLocationRaw // Router-Link
href?: string // Externer Link
// Button-Typ
type?: 'button' | 'submit'
as?: 'button' | 'a' | 'nuxt-link' | 'router-link' | Component // polymorphes Rendering
type?: 'button' | 'submit' | 'reset'
// Icon: slot-basiert (<template #icon>), nicht prop-basiert
}
```
**Nicht übernommen:**
- `bullet` → zu spezifisch, kann mit `circle` + custom size erreicht werden
- `hover` prop → unnötig, CSS :hover reicht
- `padding` prop → sollte über size geregelt werden
---
### Verwendete Design-Tokens (tatsächlich genutzt)
@ -636,11 +612,11 @@ interface OsButtonProps {
---
### Offene Fragen
### Offene Fragen ✅ (alle gelöst)
1. **secondary Variante:** Styleguide hat `secondary` (blau), Webapp nicht. Wird es gebraucht?
2. **x-large Size:** Styleguide hat `x-large` in CSS, aber nicht als Prop. Übernehmen?
3. **bullet Form:** Webapp-spezifisch. Brauchen wir das in OsButton?
1. ~~secondary Variante~~ → ✅ Ja, implementiert als `variant="secondary"`
2. ~~x-large Size~~ → ✅ Implementiert als `size="xl"`
3. ~~bullet Form~~ → ✅ Nicht übernommen, `circle` + custom CSS reicht
---
@ -956,120 +932,120 @@ interface OsDropdownProps {
## Priorisierung der Komponenten
### Tier 1: Kern-Komponenten (höchste Priorität)
### Tier 1: Kern-Komponenten
Diese Komponenten sind die Basis für alle anderen und sollten zuerst migriert werden:
| # | Komponente | Status |
|---|------------|--------|
| 1 | **OsButton** | ✅ 133 Buttons in 79 Dateien, BaseButton gelöscht |
| 2 | **OsIcon** | ✅ 131 Nutzungen, 82 Ocelot-Icons, BaseIcon gelöscht |
| 3 | **OsSpinner** | ✅ 4 Spinner migriert, LoadingSpinner gelöscht |
| 4 | **OsCard** | ✅ ~30 Dateien, BaseCard gelöscht |
| # | Komponente | Begründung | Abhängigkeiten |
|---|------------|------------|----------------|
| 1 | **OsButton** | Meistgenutzte Komponente, Basis für viele Features | OsIcon |
| 2 | **OsIcon** | Wird von Button, Menu, etc. benötigt | - |
| 3 | **OsSpinner** | Loading-States für Button, Modal, etc. | - |
| 4 | **OsCard** | Layout-Basis für viele Komponenten | - |
### Tier A: Triviale ds-* → Plain HTML ✅
### Tier 2: Layout & Feedback (mittlere Priorität)
| # | Komponente | Status |
|---|------------|--------|
| — | ds-section, ds-placeholder, ds-tag, ds-list, ds-list-item | ✅ → HTML-Elemente + CSS-Klassen |
| — | ds-container, ds-heading, ds-text | ✅ → HTML-Elemente + CSS-Klassen |
| — | ds-space | ✅ → div + Margin-Utility-Klassen |
| — | ds-flex, ds-flex-item | ✅ → HTML + CSS @media Queries |
| # | Komponente | Begründung | Abhängigkeiten |
|---|------------|------------|----------------|
| 5 | **OsModal** | Dialoge, Bestätigungen, Formulare | OsButton, OsCard |
| 6 | **OsDropdown** | Dropdown-Menüs, Selects | OsButton |
| 7 | **OsAvatar** | Benutzerprofile, Kommentare | - |
| 8 | **OsInput** | Formulare | - |
### Tier B: Einfache ds-* → Plain HTML (ausstehend)
### Tier 3: Navigation & Typography (niedrigere Priorität)
| # | Komponente | Dateien | Ziel |
|---|------------|---------|------|
| — | ds-chip | 5 | `<span class="ds-chip">` |
| — | ds-number | 5 | `<div class="ds-number">` |
| — | ds-grid / ds-grid-item | 10 | CSS Grid |
| — | ds-radio | 1 | native `<input type="radio">` |
| # | Komponente | Begründung | Abhängigkeiten |
|---|------------|------------|----------------|
| 9 | **OsMenu** | Navigation (weniger kritisch) | OsMenuItem |
| 10 | **OsMenuItem** | Menu-Items | - |
| 11 | **OsHeading** | Überschriften | - |
| 12 | **OsText** | Text-Formatierung | - |
### Tier 2: Layout & Feedback (ausstehend)
### Tier 4: Spezial-Komponenten (später)
| # | Komponente | Dateien | Abhängigkeiten |
|---|------------|---------|----------------|
| 5 | **OsModal** | 7 | OsButton, OsCard |
| 6 | **OsDropdown** | — | OsButton |
| 7 | **OsAvatar** | — | - |
| 8 | **OsInput** | 23 | gekoppelt mit ds-form (18 Dateien) |
| # | Komponente | Begründung |
|---|------------|------------|
| 13 | OsSelect | Komplexere Formular-Komponente |
| 14 | OsTable | Datentabellen |
| 15 | OsTag/OsChip | Tags und Badges |
### Tier 3: Navigation (ausstehend)
| # | Komponente | Dateien | Abhängigkeiten |
|---|------------|---------|----------------|
| 9 | **OsMenu** | 11 | OsMenuItem |
| 10 | **OsMenuItem** | 6 | - |
### Tier 4: Spezial-Komponenten (ausstehend)
| # | Komponente | Dateien |
|---|------------|---------|
| 11 | OsSelect | 3 |
| 12 | OsTable | 7 |
| 13 | ds-form → HTML `<form>` oder OsForm | 18 |
> **Hinweis:** OsHeading, OsText, OsTag sind nicht mehr geplant — wurden zu Plain HTML migriert (Tier A).
---
## Finaler Konsolidierungsplan
> **Hinweis:** "Tier 1/2/3" bezeichnet die Migrations-Reihenfolge innerhalb von Phase 4 (Komponenten-Migration).
> Dies ist unabhängig von den Haupt-Phasen 0-5 des Projekts.
> **Hinweis:** "Tier 1/A/B/2/3/4" bezeichnet die Migrations-Reihenfolge innerhalb von Phase 4.
### Tier 1: Kern-Komponenten
### Tier 1: Kern-Komponenten
```
1. OsIcon
└── Vereint: DsIcon (Styleguide), BaseIcon (Webapp)
└── Token: Keine eigenen (nur Größen via Props)
2. OsSpinner
└── Vereint: DsSpinner (Styleguide), LoadingSpinner (Webapp)
└── Token: Farben, Größen
3. OsButton
└── Vereint: DsButton (Styleguide), BaseButton (Webapp)
└── NICHT übernommen: Feature-Buttons (FollowButton, etc.)
└── Token: Farben, Größen, Border-Radius, Spacing
4. OsCard
└── Vereint: DsCard (Styleguide), BaseCard (Webapp)
└── Token: Shadows, Border-Radius, Spacing
1. OsIcon ✅ Vereint: DsIcon + BaseIcon → 82 Ocelot-Icons
2. OsSpinner ✅ Vereint: DsSpinner + LoadingSpinner
3. OsButton ✅ Vereint: DsButton + BaseButton → 133 Buttons in 79 Dateien
4. OsCard ✅ Vereint: DsCard + BaseCard → ~30 Dateien
```
### Tier 2: Layout & Feedback
### Tier A: Triviale ds-* Wrapper → Plain HTML ✅
```
5. OsModal
└── Basis: DsModal (Styleguide) - bereits gut!
└── Feature-Modals bleiben in Webapp, nutzen OsModal
└── Token: Z-Index, Shadows, Spacing
6. OsDropdown (NEU!)
└── Basis: Dropdown (Webapp)
└── Erkenntnis: Wichtiger als gedacht!
└── Token: Spacing, Shadows
7. OsAvatar
└── Vereint: DsAvatar (Styleguide), ProfileAvatar (Webapp)
└── Token: Größen, Border-Radius
8. OsInput
└── Basis: DsInput (Styleguide), InputField Patterns (Webapp)
└── Token: Border, Farben, Spacing
ds-section, ds-placeholder, ds-tag, ds-list, ds-list-item ✅ → HTML + CSS-Klassen
ds-container, ds-heading, ds-text ✅ → HTML + CSS-Klassen
ds-space ✅ → div + Margin-Utilities
ds-flex, ds-flex-item ✅ → HTML + CSS @media Queries
```
### Tier 3: Navigation
### Tier B: Einfache ds-* → Plain HTML (ausstehend)
```
9. OsMenu + OsMenuItem
└── Basis: DsMenu/DsMenuItem (Styleguide)
└── Feature-Menus bleiben in Webapp
└── Token: Spacing, Farben
ds-chip, ds-number, ds-grid/ds-grid-item, ds-radio → Plain HTML + CSS
```
### Tier 2-4: UI-Library (ausstehend)
```
5. OsModal → Basis: DsModal, Feature-Modals bleiben in Webapp
6. OsDropdown → Basis: Dropdown (Webapp) — wichtiger als gedacht!
7. OsAvatar → Vereint: DsAvatar + ProfileAvatar
8. OsInput → Basis: DsInput, gekoppelt mit ds-form
9. OsMenu → Basis: DsMenu/DsMenuItem
10. OsSelect → Basis: DsSelect
11. OsTable → Basis: DsTable
```
---
## Erkenntnisse aus der Analyse
### Was funktioniert gut (beibehalten):
1. **DsModal als Basis** - Feature-Modals nutzen bereits DsModal
2. **BaseButton als Standard** - Webapp hat konsolidiert auf BaseButton
3. **Dropdown-Pattern** - Funktioniert gut mit v-popover
### Was funktioniert gut:
1. **DsModal als Basis** - Feature-Modals nutzen bereits DsModal → OsModal wird gleich funktionieren
2. **Dropdown-Pattern** - Funktioniert gut mit v-popover
3. **Tier A Migration** - 10 ds-* Wrapper durch HTML + CSS ersetzt, kein Funktionsverlust
### Was problematisch ist (verbessern):
1. **Button-Varianten** - Zu viele unterschiedliche Buttons
2. **Inkonsistente Naming** - ds-* vs base-* vs kebab-case
3. **Doppelte Komponenten** - Logo, Icon, Card existieren doppelt
### Was gelöst wurde: ✅
1. ~~Button-Varianten~~ → OsButton mit CVA-Varianten vereinheitlicht
2. ~~Inkonsistente Naming~~ → os-* Prefix für Library, ds-* CSS-Klassen temporär beibehalten
3. ~~Doppelte Komponenten~~ → BaseCard, BaseIcon, LoadingSpinner gelöscht (3/5 Duplikate aufgelöst)
4. ~~Layout-Shift bei ds-flex~~ → CSS @media Queries statt JavaScript window.innerWidth
### Was überflüssig ist (nicht migrieren):
1. **bullet Button** - Zu spezifisch, kann mit circle erreicht werden
2. **hover Prop** - CSS :hover reicht
3. **Viele Feature-Buttons** - Behalten Business-Logik, nutzen OsButton
### Noch offen:
1. **Logo** - Existiert doppelt (Webapp + Styleguide)
2. **Modal** - Existiert doppelt (Webapp Modal.vue ist Modal-Router, DsModal ist UI)
3. **ds-form Kopplung** - ds-input und ds-form sind stark gekoppelt (Schema-Validation)
---
@ -1138,7 +1114,7 @@ $box-shadow-small-inset: inset 0 0 0 1px rgba(0,0,0,.05)
## Phase 3: Webapp-Integration (Tracking)
### OsButton Migration - Abgeschlossen (132/132) ✅
### OsButton Migration - Abgeschlossen (133/133) ✅
| # | Datei | Button | Status |
|---|-------|--------|--------|
@ -1181,15 +1157,9 @@ $box-shadow-small-inset: inset 0 0 0 1px rgba(0,0,0,.05)
| `fullWidth` Prop | ✅ |
| `type` Prop (button/submit/reset) | ✅ |
### Nächste Schritte
### Status
1. Snapshot-Dateien aktualisieren
2. Test-Selektoren anpassen
3. BaseButton.vue ggf. entfernen
4. Phase 4: Weitere Komponenten (OsIcon, OsCard, OsModal, ...)
### Integrations-Protokoll
| Datum | Aktion | Details |
|-------|--------|---------|
| 2026-02-08 | Analyse | 6 Einsatzstellen identifiziert, 2 minimal (nur variant) |
**OsButton Migration: ✅ Vollständig abgeschlossen.**
- BaseButton.vue gelöscht, base-components.js Plugin entfernt
- Alle Tests, Snapshots, Cypress E2E-Selektoren aktualisiert
- Nächster Schritt: Tier B (ds-chip, ds-number, ds-grid, ds-radio) oder Tier 2 (OsModal)

View File

@ -81,10 +81,10 @@ Phase 0: ██████████ 100% (6/6 Aufgaben) ✅
Phase 1: ██████████ 100% (6/6 Aufgaben) ✅
Phase 2: ██████████ 100% (26/26 Aufgaben) ✅
Phase 3: ██████████ 100% (24/24 Aufgaben) ✅ - Webapp-Integration komplett
Phase 4: █████░░░░░ 47% (8/17 Aufgaben) - OsButton ✅, OsIcon ✅, System-Icons ✅, BaseIcon→OsIcon Migration ✅, OsSpinner ✅, Spinner Webapp-Migration ✅, OsCard ✅, BaseCard→OsCard Migration ✅
Phase 4: █████░░░░░ 46% (12/26 Aufgaben) - Tier 1 ✅, Tier A ✅, Infra ✅ | Tier B, Tier 2-4 ausstehend
Phase 5: ░░░░░░░░░░ 0% (0/7 Aufgaben)
───────────────────────────────────────
Gesamt: ████████░░ 81% (70/86 Aufgaben)
Gesamt: ████████░░ 78% (74/95 Aufgaben)
```
### Katalogisierung (Details in KATALOG.md)
@ -177,17 +177,54 @@ BaseIcon → OsIcon Webapp-Migration: ✅
├─ Jest Mocks: @ocelot-social/ui/ocelot für ocelotIcons in Tests
├─ Tests aktualisiert: 911/939 Tests bestanden (3 pre-existing failures)
└─ 0 base-icon/BaseIcon Referenzen verbleibend
Tier A ds-* → Plain HTML + CSS: ✅
├─ 10 triviale Vue-Wrapper-Komponenten durch HTML-Elemente + CSS-Klassen ersetzt
├─ ~450 Nutzungen in ~90 Dateien migriert
├─ _ds-compat.scss: Utility-Klassen für Margins (.ds-mb-*, .ds-mt-*, .ds-my-*),
│ Flex (.ds-flex, .ds-flex-item, .ds-flex-gap-*), Centered (.ds-space-centered)
├─ ds-flex/ds-flex-item: JavaScript window.innerWidth → CSS @media Queries
│ (kein Layout-Shift bei SSR, bessere Performance)
├─ system.css bleibt geladen — bestehende CSS-Klassen funktionieren weiter
├─ Verbleibend: 13 ds-* Komponenten (Tier B: 4 einfache, Tier C: 6 komplexe → UI-Library)
└─ 0 Tier-A ds-* Komponenten-Tags verbleibend
```
---
## Aktueller Stand
**Letzte Aktualisierung:** 2026-02-19 (Session 25)
**Letzte Aktualisierung:** 2026-02-19 (Session 27)
**Aktuelle Phase:** Phase 4 - OsIcon ✅, BaseIcon → OsIcon Migration ✅, OsSpinner ✅, Spinner Webapp-Migration ✅, OsCard ✅, BaseCard → OsCard Migration ✅
**Aktuelle Phase:** Phase 4 - OsIcon ✅, BaseIcon → OsIcon Migration ✅, OsSpinner ✅, Spinner Webapp-Migration ✅, OsCard ✅, BaseCard → OsCard Migration ✅, Tier A ds-* → Plain HTML ✅
**Zuletzt abgeschlossen (Session 25 - BaseCard → OsCard Webapp-Migration):**
**Zuletzt abgeschlossen (Session 27 - Tier A: ds-* Komponenten → Plain HTML):**
- [x] `_ds-compat.scss` erstellt (Utility-Klassen für Margins, Flex, Centered)
- [x] `ds-section``<section class="ds-section">` (5 Dateien)
- [x] `ds-placeholder``<div class="ds-placeholder">` (4 Dateien)
- [x] `ds-tag``<span class="ds-tag">` (2 Dateien)
- [x] `ds-list``<ul class="ds-list">` (4 Dateien)
- [x] `ds-list-item``<li class="ds-list-item">` (8 Dateien)
- [x] `ds-container``<div class="ds-container ds-container-{width}">` (14 Dateien, 12 Dateien)
- [x] `ds-heading``<h1-h4 class="ds-heading ds-heading-h{n}">` (31 Nutzungen, 25 Dateien)
- [x] `ds-text``<p/div class="ds-text ds-text-{color} ds-text-size-{size}">` (80 Nutzungen, 42 Dateien)
- [x] `ds-space``<div class="ds-mb-{size}">` / `<div class="ds-my-{size}">` (139 Nutzungen, 55+ Dateien)
- [x] `ds-flex` / `ds-flex-item` → Plain HTML + CSS Media Queries (103 Nutzungen, 29 Dateien)
- [x] Responsive Layouts: JavaScript `window.innerWidth` → CSS `@media` Queries (kein Layout-Shift)
- [x] Bugfix: `<p>` mit Block-Level-Kindern → `<div>` (DateTimeRange.vue, verify.vue)
- [x] Test-Fix: Empty.spec.js `attributes().margin``classes().toContain('ds-my-xxx-small')`
- [x] 0 Tier-A `ds-*` Komponenten-Tags verbleibend
**Verbleibende ds-* Komponenten (13 Typen):**
- Tier B (→ Plain HTML): ds-chip (5), ds-number (5), ds-grid/ds-grid-item (10), ds-radio (1)
- Tier C (→ UI-Library): ds-input (23), ds-form (18), ds-modal (7), ds-menu/ds-menu-item (17), ds-table (7), ds-select (3)
**Zuvor abgeschlossen (Session 26 - CodeRabbit Review Fixes):**
- [x] Cypress: `.os-card .title``.os-card > .title` (Kind-Kombinator statt Nachfahren)
- [x] OsCard.spec.ts: `compareDocumentPosition()` Bitmask-Assertion `!== 0` statt `.toBe(true)`
- [x] Maintenance-App: `@ocelot-social/ui` Abhängigkeit + `./nuxt.config.js` Import als pre-existing (kein Scope) bewertet
**Zuvor abgeschlossen (Session 25 - BaseCard → OsCard Webapp-Migration):**
- [x] ~30 Webapp-Dateien: `<base-card>``<os-card>` mit lokalen Imports
- [x] 3 Template-Dateien mit #imageColumn/#topMenu Slots → inline Layout (LoginForm, RegistrationSlider, password-reset)
- [x] CSS: `.os-card.--columns` Layout in main.scss (flex, image-column, content-column, top-menu, responsive)
@ -300,7 +337,12 @@ BaseIcon → OsIcon Webapp-Migration: ✅
**Nächste Schritte:**
- [x] OsSpinner Webapp-Migration (DsSpinner + LoadingSpinner → OsSpinner) ✅
- [x] OsCard Komponente + BaseCard → OsCard Webapp-Migration ✅
- [x] Tier A: 10 triviale ds-* Wrapper → Plain HTML + CSS ✅
- [ ] Tier B: ds-chip, ds-number, ds-grid/ds-grid-item, ds-radio → Plain HTML
- [ ] Weitere Tier 2 Komponenten (OsModal, OsDropdown, OsAvatar, OsInput)
- [ ] ds-form + ds-input → OsForm + OsInput (stark gekoppelt, 18+23 Dateien)
- [ ] ds-menu / ds-menu-item → OsMenu / OsMenuItem
- [ ] ds-table → OsTable, ds-select → OsSelect
- [ ] Browser-Fehler untersuchen: `TypeError: Cannot read properties of undefined (reading 'heartO')` (ocelotIcons undefined im Browser trotz korrekter Webpack-Aliase)
**Manuelle Setup-Aufgaben (außerhalb Code):**
@ -548,37 +590,51 @@ Jeder migrierte Button muss manuell geprüft werden: Normal, Hover, Focus, Activ
- [ ] Alle Unit-Tests bestehen
- [ ] Dokumentation aktualisieren
### Phase 4: Komponenten-Migration (15 Komponenten + 2 Infrastruktur)
### Phase 4: Komponenten-Migration
**Tier 1: Kern-Komponenten**
**Tier 1: Kern-Komponenten (UI-Library)**
- [x] OsIcon (vereint DsIcon + BaseIcon) ✅ System-Icons + vite-svg-icon Plugin
- [x] OsSpinner (vereint DsSpinner + LoadingSpinner) ✅ OsButton nutzt OsSpinner als Komponente
- [x] OsSpinner Webapp-Migration ✅ 4 Spinner migriert, LoadingSpinner gelöscht, Admin ApolloQuery→$apollo.loading
- [x] OsButton (vereint DsButton + BaseButton) ✅ Entwickelt in Phase 2
- [x] OsCard (vereint DsCard + BaseCard) ✅ Webapp-Migration abgeschlossen, BaseCard gelöscht
- [x] OsSpinner Webapp-Migration ✅ 4 Spinner migriert, LoadingSpinner gelöscht
- [x] OsButton (vereint DsButton + BaseButton) ✅ 133 Buttons in 79 Dateien
- [x] OsCard (vereint DsCard + BaseCard) ✅ ~30 Dateien, BaseCard gelöscht
**Tier 2: Layout & Feedback**
- [ ] OsModal (Basis: DsModal)
**Tier A: Triviale ds-* Wrapper → Plain HTML + CSS** ✅
- [x] _ds-compat.scss Utility-Klassen (Margins, Flex, Centered)
- [x] ds-section, ds-placeholder, ds-tag, ds-list, ds-list-item → HTML + CSS-Klassen
- [x] ds-container, ds-heading, ds-text → HTML + CSS-Klassen
- [x] ds-space → div + Margin-Utility-Klassen (139 Nutzungen)
- [x] ds-flex / ds-flex-item → HTML + CSS @media Queries (103 Nutzungen)
**Tier B: Einfache ds-* → Plain HTML (ausstehend)**
- [ ] ds-chip (5 Dateien) → `<span class="ds-chip">`
- [ ] ds-number (5 Dateien) → `<div class="ds-number">`
- [ ] ds-grid / ds-grid-item (10 Dateien) → CSS Grid
- [ ] ds-radio (1 Datei) → native `<input type="radio">`
**Tier 2: Layout & Feedback (UI-Library)**
- [ ] OsModal (Basis: DsModal, 7 Dateien)
- [ ] OsDropdown (Basis: Webapp Dropdown)
- [ ] OsAvatar (vereint DsAvatar + ProfileAvatar)
- [ ] OsInput (Basis: DsInput)
- [ ] OsInput (Basis: DsInput, 23 Dateien — gekoppelt mit ds-form)
**Tier 3: Navigation & Typography**
- [ ] OsMenu (Basis: DsMenu)
- [ ] OsMenuItem (Basis: DsMenuItem)
- [ ] OsHeading (Basis: DsHeading)
- [ ] OsText (Basis: DsText)
**Tier 3: Navigation (UI-Library)**
- [ ] OsMenu (Basis: DsMenu, 11 Dateien)
- [ ] OsMenuItem (Basis: DsMenuItem, 6 Dateien)
**Tier 4: Spezial-Komponenten**
- [ ] OsSelect
- [ ] OsTable
- [ ] OsTag
- [ ] OsSelect (3 Dateien)
- [ ] OsTable (7 Dateien)
- [ ] ds-form → Plain HTML `<form>` oder OsForm (18 Dateien)
**Infrastruktur**
- [x] System-Icons einrichten ✅ vite-svg-icon Plugin, 3 System-Icons, Ocelot-Icons Entry-Point
- [x] BaseIcon → OsIcon Webapp-Migration ✅ 131 Nutzungen, 82 Ocelot-Icons, 0 BaseIcon verbleibend
- [ ] CI docs-check Workflow (JSDoc-Coverage, README-Aktualität)
> **Hinweis:** ds-heading, ds-text, ds-tag wurden zu Plain HTML migriert (Tier A).
> OsHeading/OsText/OsTag als UI-Library-Komponenten sind daher nicht mehr geplant.
### Phase 5: Finalisierung
- [ ] Alle Komponenten migriert und getestet
- [ ] Alte Komponenten aus Vue 2 Projekt entfernt
@ -1671,6 +1727,16 @@ Bei der Migration werden:
| 2026-02-19 | **BaseCard gelöscht** | BaseCard.vue Komponente + base-components.js Plugin entfernt; nuxt.config, maintenance config, testSetup bereinigt |
| 2026-02-19 | **CSS-Fixes** | ContributionForm Media-Query Selektoren, ProfileList Spezifität, InternalPage $space-small, OsCard highlight outline-1 Tests |
| 2026-02-19 | **Code-Quality** | SocialMedia Props typisiert, LoginForm querySelector, redundante client-only entfernt, NotificationsTable optional chaining, HashtagsFilter doppeltes Mounting |
| 2026-02-19 | **Review Fixes (Session 26)** | Cypress Kind-Kombinator `.os-card > .title`, OsCard.spec.ts Bitmask-Assertion fix, Maintenance-App Abhängigkeiten als pre-existing bewertet |
| 2026-02-19 | **Tier A Migration (Session 27)** | 10 triviale ds-* Vue-Wrapper → Plain HTML + CSS-Klassen; `_ds-compat.scss` Utility-Klassen; ~90 Dateien geändert |
| 2026-02-19 | **ds-section/placeholder/tag/list** | 19 Nutzungen in 13 Dateien → HTML-Elemente mit bestehenden CSS-Klassen aus system.css |
| 2026-02-19 | **ds-container** | 14 Nutzungen in 12 Dateien → `<div class="ds-container ds-container-{width}">` |
| 2026-02-19 | **ds-heading** | 31 Nutzungen in 25 Dateien → `<h1-h4 class="ds-heading ds-heading-h{n}">` mit soft/no-margin/align |
| 2026-02-19 | **ds-text** | 80 Nutzungen in 42 Dateien → `<p/div class="ds-text ds-text-{color} ds-text-size-{size}">` |
| 2026-02-19 | **ds-space** | 139 Nutzungen in 55+ Dateien → `<div class="ds-mb-{size}">` / `<div class="ds-my-{size}">`; neue Utility-Klassen in _ds-compat.scss |
| 2026-02-19 | **ds-flex/ds-flex-item** | 103 Nutzungen in 29 Dateien → Plain HTML + CSS `@media` Queries; JS window.innerWidth → CSS Media Queries; `gap` statt negative-margin/padding |
| 2026-02-19 | **HTML-Validierung Bugfix** | `<p>` mit Block-Level-Kindern → `<div>` in DateTimeRange.vue und verify.vue |
| 2026-02-19 | **Test-Fix** | Empty.spec.js: `attributes().margin``classes().toContain('ds-my-xxx-small')` |
---
@ -1680,11 +1746,20 @@ Bei der Migration werden:
### Zusammenfassung (aus KATALOG.md)
| Quelle | Gesamt | Analysiert | Duplikate | Zu migrieren |
|--------|--------|------------|-----------|--------------|
| Webapp | 139 | ✅ | 5 | Priorisiert |
| Styleguide | 38 | ✅ | 5 | Priorisiert |
| **Gesamt** | **177** | **✅** | **5 direkte + 3 Familien** | **15 Kern-Komponenten** |
| Quelle | Gesamt | Status |
|--------|--------|--------|
| Webapp | 139 | ✅ Katalogisiert |
| Styleguide | 38 | ✅ Katalogisiert — 23 in Webapp genutzt |
**Styleguide-Migration:**
| Status | Komponenten |
|--------|------------|
| ✅ UI-Library | OsButton, OsIcon, OsSpinner, OsCard (4) |
| ✅ → Plain HTML | Section, Placeholder, Tag, List, ListItem, Container, Heading, Text, Space, Flex, FlexItem (11) — Tier A |
| ⬜ → Plain HTML | Chip, Number, Grid, GridItem, Radio (5) — Tier B |
| ⬜ → UI-Library | Modal, Input, Menu, MenuItem, Select, Table (6) — Tier 2-4 |
| ⬜ Nicht genutzt | Code, CopyField, FormItem, InputError, InputLabel, Page, PageTitle, Logo, Avatar, TableCol, TableHeadCol (11) |
| ⬜ Offen | Form (18 Dateien — HTML `<form>` oder OsForm?) |
---

View File

@ -0,0 +1,67 @@
// ==========================================================
// DS-COMPAT: Temporäre Utility-Klassen für ds-* Migration
// TODO(tailwind): Durch Tailwind-Utilities ersetzen
// Grep: ds-mb-, ds-mt-, ds-my-, ds-space-centered, ds-flex
// ==========================================================
// ds-space Ersatz Margin-Bottom
.ds-mb-xxx-small { margin-bottom: $space-xxx-small; }
.ds-mb-xx-small { margin-bottom: $space-xx-small; }
.ds-mb-x-small { margin-bottom: $space-x-small; }
.ds-mb-small { margin-bottom: $space-small; }
.ds-mb-base { margin-bottom: $space-base; }
.ds-mb-large { margin-bottom: $space-large; }
.ds-mb-x-large { margin-bottom: $space-x-large; }
.ds-mb-xx-large { margin-bottom: $space-xx-large; }
// ds-space Ersatz Margin-Top
.ds-mt-xxx-small { margin-top: $space-xxx-small; }
.ds-mt-xx-small { margin-top: $space-xx-small; }
.ds-mt-x-small { margin-top: $space-x-small; }
.ds-mt-small { margin-top: $space-small; }
.ds-mt-base { margin-top: $space-base; }
.ds-mt-large { margin-top: $space-large; }
.ds-mt-x-large { margin-top: $space-x-large; }
.ds-mt-xx-large { margin-top: $space-xx-large; }
// ds-space Ersatz Margin Y (top + bottom)
.ds-my-xxx-small { margin-top: $space-xxx-small; margin-bottom: $space-xxx-small; }
.ds-my-xx-small { margin-top: $space-xx-small; margin-bottom: $space-xx-small; }
.ds-my-x-small { margin-top: $space-x-small; margin-bottom: $space-x-small; }
.ds-my-small { margin-top: $space-small; margin-bottom: $space-small; }
.ds-my-base { margin-top: $space-base; margin-bottom: $space-base; }
.ds-my-large { margin-top: $space-large; margin-bottom: $space-large; }
.ds-my-x-large { margin-top: $space-x-large; margin-bottom: $space-x-large; }
.ds-my-xx-large { margin-top: $space-xx-large; margin-bottom: $space-xx-large; }
// ds-space centered
.ds-space-centered {
display: flex;
flex: 1;
text-align: center;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
// ds-list-item bullet icon (replaces DsListItem Vue component's angle-right prefix)
.ds-list-item::before {
content: '';
flex: 0 0 1.5em;
height: 1.2em;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='%2370677e'%3E%3Cpath d='M12.969 4.281l11 11 .688.719-.688.719-11 11-1.438-1.438L21.812 16 11.531 5.719z'/%3E%3C/svg%3E") no-repeat left center;
background-size: 0.6em;
}
// ds-flex Ersatz
.ds-flex { display: flex; flex-wrap: wrap; }
.ds-flex-no-wrap { flex-wrap: nowrap; }
.ds-flex-centered { align-items: center; justify-content: center; }
.ds-flex-item { flex: 1 0 0; min-width: 0; }
.ds-flex-gap-xxx-small { gap: $space-xxx-small; }
.ds-flex-gap-xx-small { gap: $space-xx-small; }
.ds-flex-gap-x-small { gap: $space-x-small; }
.ds-flex-gap-small { gap: $space-small; }
.ds-flex-gap-base { gap: $space-base; }
.ds-flex-gap-large { gap: $space-large; }

View File

@ -151,13 +151,10 @@ body.dropdown-open {
overflow: hidden;
}
.os-card > .ds-section {
padding: 0;
margin: -$space-base;
.ds-container {
.os-card > .ds-section,
.os-card > .os-card__content > .ds-section {
padding: $space-base;
}
margin: -$space-base;
}
.os-card {

View File

@ -28,9 +28,9 @@
{{ $t('login.hello') }}
<b>{{ userName }}</b>
<template v-if="user.role !== 'user'">
<ds-text color="softer" size="small" style="margin-bottom: 0">
<p class="ds-text ds-text-softer ds-text-size-small" style="margin-bottom: 0">
{{ user.role | camelCase }}
</ds-text>
</p>
</template>
<hr />
<ds-menu :routes="routes" :matcher="matcher">

View File

@ -1,8 +1,11 @@
<template>
<ds-tag class="category-tag" :class="filterActive ? 'filterActive' : ''">
<span
class="ds-tag ds-tag-size-base ds-tag-medium category-tag"
:class="filterActive ? 'filterActive' : ''"
>
<os-icon :icon="resolvedIcon" />
{{ name }}
</ds-tag>
</span>
</template>
<script>

View File

@ -1,6 +1,6 @@
<template>
<div class="add-chat-room-by-user-search">
<ds-flex class="headline">
<div class="ds-flex headline">
<h2 class="title">{{ $t('chat.addRoomHeadline') }}</h2>
<os-button
class="close-button"
@ -15,11 +15,11 @@
<os-icon :icon="icons.close" />
</template>
</os-button>
</ds-flex>
<ds-space margin-bottom="small" />
<ds-space>
</div>
<div class="ds-mb-small"></div>
<div class="ds-mb-large">
<select-user-search :id="id" ref="selectUserSearch" @select-user="selectUser" />
</ds-space>
</div>
</div>
</template>

View File

@ -32,8 +32,8 @@
@open-file="openFile($event.detail[0].file.file)"
>
<div v-if="selectedRoom && selectedRoom.roomId" slot="room-options" class="chat-room-options">
<ds-flex v-if="singleRoom">
<ds-flex-item centered class="single-chat-bubble">
<div v-if="singleRoom" class="ds-flex">
<div class="ds-flex-item single-chat-bubble" style="align-self: center">
<os-button
as="nuxt-link"
:to="{ name: 'chat' }"
@ -47,8 +47,8 @@
<os-icon :icon="icons.expand" />
</template>
</os-button>
</ds-flex-item>
<ds-flex-item centered>
</div>
<div class="ds-flex-item" style="align-self: center">
<div class="vac-svg-button vac-room-options">
<slot name="menu-icon">
<os-button
@ -65,8 +65,8 @@
</os-button>
</slot>
</div>
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
<div slot="room-header-avatar">

View File

@ -2,7 +2,7 @@
<div class="Sliders">
<slot :name="'header'" />
<ds-heading
<h3
v-if="
sliderData.sliders[sliderIndex].titleIdent &&
((typeof sliderData.sliders[sliderIndex].titleIdent === 'string' &&
@ -13,7 +13,7 @@
sliderData.sliders[sliderIndex].titleIdent.data,
).length > 0))
"
size="h3"
class="ds-heading ds-heading-h3"
>
{{
(typeof sliderData.sliders[sliderIndex].titleIdent === 'string' &&
@ -24,12 +24,12 @@
sliderData.sliders[sliderIndex].titleIdent.data,
))
}}
</ds-heading>
</h3>
<slot :name="sliderData.sliders[sliderIndex].name" />
<ds-flex>
<ds-flex-item v-if="multipleSliders" :centered="true">
<div class="ds-flex">
<div v-if="multipleSliders" class="ds-flex-item" style="align-self: center">
<div
v-for="(slider, index) in sliderData.sliders"
:key="slider.name"
@ -49,8 +49,8 @@
@click="sliderData.sliderSelectorCallback(index)"
/>
</div>
</ds-flex-item>
<ds-flex-item>
</div>
<div class="ds-flex-item">
<os-button
:style="multipleSliders && 'float: right'"
variant="primary"
@ -69,8 +69,8 @@
</template>
{{ $t(sliderData.sliders[sliderIndex].button.titleIdent) }}
</os-button>
</ds-flex-item>
</ds-flex>
</div>
</div>
<slot :name="'footer'" />
</div>

View File

@ -31,7 +31,7 @@
<os-icon :icon="icons.questionCircle" />
</page-params-link>
</div>
<ds-space margin-top="base" />
<div class="ds-mt-base ds-mb-large"></div>
<ds-input
model="title"
:placeholder="$t('contribution.title')"
@ -57,7 +57,7 @@
<!-- Eventdata -->
<div v-if="createEvent" class="eventDatas">
<hr />
<ds-space margin-top="x-small" />
<div class="ds-mt-x-small ds-mb-large"></div>
<ds-grid>
<ds-grid-item class="event-grid-item">
<!-- <label>Beginn</label> -->
@ -147,7 +147,7 @@
{{ $t('post.viewEvent.eventIsOnline') }}
</div>
</div>
<ds-space margin-top="x-small" />
<div class="ds-mt-x-small ds-mb-large"></div>
<categories-select
v-if="categoriesActive"
model="categoryIds"
@ -161,18 +161,17 @@
{{ formData.categoryIds.length }} / 3
<os-icon v-if="errors && errors.categoryIds" :icon="icons.warning" />
</ds-chip>
<ds-flex class="buttons-footer" gutter="xxx-small">
<ds-flex-item width="3.5" class="buttons-footer-helper">
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
<div class="ds-flex ds-flex-gap-xxx-small buttons-footer">
<div style="flex: 3.5 0 0" class="buttons-footer-helper">
<!-- TODO => remove v-html! only text ! no html! security first! -->
<ds-text
<p
class="ds-text"
v-if="showGroupHint"
v-html="$t('contribution.visibleOnlyForMembersOfGroup', { name: groupName })"
/>
<!-- eslint-enable vue/no-v-text-v-html-on-component -->
</ds-flex-item>
<ds-flex-item width="0.15" />
<ds-flex-item class="action-buttons-group" width="2">
</div>
<div style="flex: 0.15 0 0"></div>
<div class="action-buttons-group" style="flex: 2 0 0">
<os-button
data-test="cancel-button"
variant="primary"
@ -194,8 +193,8 @@
</template>
{{ $t('actions.save') }}
</os-button>
</ds-flex-item>
</ds-flex>
</div>
</div>
</os-card>
</template>
</ds-form>

View File

@ -1,5 +1,8 @@
<template>
<ds-text class="date-time-range" align="left" color="soft" :size="size">
<div
class="ds-text ds-text-left ds-text-soft date-time-range"
:class="size && 'ds-text-size-' + size"
>
<div class="date-time-row">
<div>
<os-icon :icon="icons.calendar" data-test="calendar" />
@ -25,7 +28,7 @@
</div>
</div>
</template>
</ds-text>
</div>
</template>
<script>

View File

@ -2,7 +2,7 @@
<a v-if="showLinkOnly" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">
{{ dataEmbedUrl }}
</a>
<ds-container v-else width="small" class="embed-component">
<div v-else class="ds-container ds-container-small embed-component">
<section class="content">
<div v-if="showEmbed" v-html="embedHtml" class="html" />
<template v-else>
@ -22,7 +22,7 @@
</section>
<aside v-if="showOverlay" class="overlay">
<h3>{{ $t('editor.embed.data_privacy_warning') }}</h3>
<ds-text>{{ $t('editor.embed.data_privacy_info') }} {{ embedPublisher }}</ds-text>
<p class="ds-text">{{ $t('editor.embed.data_privacy_info') }} {{ embedPublisher }}</p>
<div class="buttons">
<os-button
@click="closeOverlay()"
@ -60,7 +60,7 @@
<os-icon :icon="icons.close" />
</template>
</os-button>
</ds-container>
</div>
</template>
<script>

View File

@ -1,7 +1,7 @@
<template>
<ds-space centered margin="xxx-small">
<ds-space margin-bottom="small" />
<ds-heading tag="h4">
<div class="ds-my-xxx-small ds-space-centered">
<div class="ds-mb-small"></div>
<h4 class="ds-heading ds-heading-h4">
{{ $t('contribution.comment.commenting-disabled.no-group-member.reason') }}
<nuxt-link
:to="{
@ -11,10 +11,10 @@
>
{{ group.name }}
</nuxt-link>
</ds-heading>
<ds-text>
</h4>
<p class="ds-text">
{{ $t('contribution.comment.commenting-disabled.no-group-member.call-to-action') }}
</ds-text>
</p>
<join-leave-button
:group="group"
:userId="$store.getters['auth/user'].id"
@ -23,7 +23,7 @@
:filled="true"
@update="updateJoinLeave"
/>
</ds-space>
</div>
</template>
<script>

View File

@ -1,12 +1,12 @@
<template>
<ds-space centered margin="xxx-small">
<ds-space margin-bottom="small" />
<ds-heading tag="h4">
<div class="ds-my-xxx-small ds-space-centered">
<div class="ds-mb-small"></div>
<h4 class="ds-heading ds-heading-h4">
{{ $t('contribution.comment.commenting-disabled.blocked-author.reason') }}
</ds-heading>
<ds-text>
</h4>
<p class="ds-text">
{{ $t('contribution.comment.commenting-disabled.blocked-author.call-to-action') }}
</ds-text>
</p>
<os-button as="nuxt-link" :to="authorLink" variant="primary" appearance="filled">
<template #icon><os-icon :icon="icons.arrowRight" /></template>
{{
@ -15,7 +15,7 @@
})
}}
</os-button>
</ds-space>
</div>
</template>
<script>

View File

@ -1,8 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CtaJoinLeaveGroup.vue mount renders 1`] = `
<div class="ds-space ds-space-centered" style="margin-top: 2px; margin-bottom: 2px;">
<div class="ds-space" style="margin-bottom: 16px;"></div>
<div class="ds-my-xxx-small ds-space-centered">
<div class="ds-mb-small"></div>
<h4 class="ds-heading ds-heading-h4">
contribution.comment.commenting-disabled.no-group-member.reason
<a>

View File

@ -1,16 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CtaUnblockAuthor.vue shallowMount renders 1`] = `
<ds-space-stub marginbottom="large" margin="xxx-small" centered="true" tag="div">
<ds-space-stub marginbottom="small" tag="div"></ds-space-stub>
<ds-heading-stub tag="h4">
<div class="ds-my-xxx-small ds-space-centered">
<div class="ds-mb-small"></div>
<h4 class="ds-heading ds-heading-h4">
contribution.comment.commenting-disabled.blocked-author.reason
</ds-heading-stub>
<ds-text-stub tag="p">
</h4>
<p class="ds-text">
contribution.comment.commenting-disabled.blocked-author.call-to-action
</ds-text-stub>
</p>
<os-button-stub as="nuxt-link" variant="primary" appearance="filled" size="md" type="button" to="[object Object]">
contribution.comment.commenting-disabled.blocked-author.button-label
</os-button-stub>
</ds-space-stub>
</div>
`;

View File

@ -46,7 +46,7 @@ describe('Empty.vue', () => {
it('sets margin to that margin', () => {
propsData.margin = 'xxx-small'
wrapper = Wrapper()
expect(wrapper.find('.hc-empty').attributes().margin).toEqual(propsData.margin)
expect(wrapper.find('.hc-empty').classes()).toContain('ds-my-xxx-small')
})
})
})

View File

@ -1,7 +1,7 @@
<template>
<div>
<ds-space class="hc-empty" centered :margin="margin">
<ds-text>
<div class="hc-empty ds-space-centered" :class="'ds-my-' + margin">
<p class="ds-text">
<img
:src="iconPath"
width="80"
@ -10,11 +10,11 @@
alt="Empty"
/>
<br />
<ds-text v-show="message" class="hc-empty-message" color="softer">
<span class="ds-text-softer hc-empty-message" v-show="message">
{{ message }}
</ds-text>
</ds-text>
</ds-space>
</span>
</p>
</div>
<slot />
</div>
</template>
@ -45,7 +45,7 @@ export default {
* Vertical spacing
*/
margin: {
type: [String, Object],
type: String,
default: 'x-large',
},
},

View File

@ -14,12 +14,12 @@
id="nonce"
icon="question-circle"
/>
<ds-text>
<p class="ds-text">
{{ $t('components.registration.email-nonce.form.description') }}
</ds-text>
<ds-text>
</p>
<p class="ds-text">
{{ $t('components.registration.email-nonce.form.click-next') }}
</ds-text>
</p>
<os-button
variant="primary"
appearance="filled"

View File

@ -1,8 +1,8 @@
<template>
<div class="add-group-member">
<h2 class="title">{{ $t('group.addUser') }}</h2>
<ds-space margin-bottom="small" />
<ds-space>
<div class="ds-mb-small"></div>
<div class="ds-mb-large">
<select-user-search :id="id" ref="selectUserSearch" @select-user="selectUser" />
<ds-modal
v-if="isOpen"
@ -16,11 +16,11 @@
@confirm="confirmModal"
@cancel="cancelModal"
>
<ds-text size="large">
<p class="ds-text ds-text-size-large">
{{ $t('group.modal.confirmAddGroupMemberText', { name: user.name }) }}
</ds-text>
</p>
</ds-modal>
</ds-space>
</div>
</div>
</template>

View File

@ -31,12 +31,12 @@
:placeholder="`${$t('group.labelSlug')} …`"
></ds-input>
<ds-space v-if="update" margin-top="small" />
<div v-if="update" class="ds-mt-small ds-mb-large"></div>
<!-- groupType -->
<ds-text class="select-label">
<p class="ds-text select-label">
{{ $t('group.type') }}
</ds-text>
</p>
<select
class="select ds-input appearance--auto"
name="groupType"
@ -69,12 +69,12 @@
rows="3"
/>
<ds-space margin-top="small" />
<div class="ds-mt-small ds-mb-large"></div>
<!-- description -->
<ds-text class="select-label">
<p class="ds-text select-label">
{{ $t('group.description') }}
</ds-text>
</p>
<editor
name="description"
model="description"
@ -89,9 +89,9 @@
</ds-chip>
<!-- actionRadius -->
<ds-text class="select-label">
<p class="ds-text select-label">
{{ $t('group.actionRadius') }}
</ds-text>
</p>
<action-radius-select
v-model="formData.actionRadius"
@change.native="changeActionRadius($event)"
@ -112,13 +112,13 @@
<!-- location -->
<location-select v-model="formData.locationName" />
<ds-space margin-top="small" />
<div class="ds-mt-small ds-mb-large"></div>
<!-- category -->
<div v-if="categoriesActive">
<ds-text class="select-label">
<p class="ds-text select-label">
{{ $t('group.categoriesTitle') }}
</ds-text>
</p>
<categories-select
model="categoryIds"
@ -131,7 +131,7 @@
</ds-chip>
</div>
<!-- submit -->
<ds-space margin-top="large">
<div class="buttons ds-mt-large ds-mb-large">
<os-button as="nuxt-link" to="/groups" variant="default" appearance="filled">
{{ $t('actions.cancel') }}
</os-button>
@ -144,7 +144,7 @@
<template #icon><os-icon :icon="icons.save" /></template>
{{ update ? $t('group.update') : $t('group.save') }}
</os-button>
</ds-space>
</div>
</template>
</ds-form>
</div>

View File

@ -1,14 +1,9 @@
<template>
<ds-flex class="group-list">
<ds-flex-item
v-for="group in groups"
:key="group.id"
:width="{ base: '98%', sm: '98%', md: '48%' }"
class="group-item"
>
<div class="ds-flex group-list">
<div v-for="group in groups" :key="group.id" class="group-list__item group-item">
<group-teaser :group="group" />
</ds-flex-item>
</ds-flex>
</div>
</div>
</template>
<script>
@ -25,6 +20,16 @@ export default {
}
</script>
<style lang="scss" scoped>
.group-list__item {
flex: 0 0 98%;
width: 98%;
}
@media #{$media-query-medium} {
.group-list__item {
flex: 0 0 48%;
width: 48%;
}
}
.group-item {
margin: 0 1% 2% 1%;
}

View File

@ -1,7 +1,7 @@
<template>
<div class="group-member">
<h2 class="title">{{ $t('group.membersListTitle') }}</h2>
<ds-space margin-bottom="small" />
<div class="ds-mb-small"></div>
<ds-table :fields="tableFields" :data="groupMembers" condensed>
<template #avatar="scope">
<nuxt-link
@ -20,9 +20,9 @@
params: { id: scope.row.user.id, slug: scope.row.user.slug },
}"
>
<ds-text>
<p class="ds-text">
<b>{{ scope.row.user.name | truncate(20) }}</b>
</ds-text>
</p>
</nuxt-link>
</template>
<template #slug="scope">
@ -32,9 +32,9 @@
params: { id: scope.row.user.id, slug: scope.row.user.slug },
}"
>
<ds-text>
<p class="ds-text">
<b>{{ `@${scope.row.user.slug}` | truncate(20) }}</b>
</ds-text>
</p>
</nuxt-link>
</template>
<template #roleInGroup="scope">

View File

@ -12,16 +12,16 @@
<div class="slug-location">
<!-- group slug -->
<div>
<ds-text color="soft">
<p class="ds-text ds-text-soft">
{{ `&${group.slug}` }}
</ds-text>
</p>
</div>
<!-- group location -->
<div class="location-item">
<ds-text v-if="group && group.location" color="soft">
<p class="ds-text ds-text-soft" v-if="group && group.location">
<os-icon :icon="icons.mapMarker" />
{{ group && group.location ? group.location.name : '' }}
</ds-text>
</p>
</div>
</div>
<!-- TODO: replace editor content with tiptap render view -->
@ -66,9 +66,9 @@
<footer class="footer">
<!-- group goal -->
<div class="labeled-chip">
<ds-text class="label-text hyphenate-text" color="soft" size="small">
<p class="ds-text ds-text-soft ds-text-size-small label-text hyphenate-text">
{{ $t('group.goal') }}
</ds-text>
</p>
<div class="chip">
<ds-chip v-if="group && group.about">{{ group ? group.about : '' }}</ds-chip>
</div>

View File

@ -1,7 +1,7 @@
<template>
<ds-tag class="hc-hashtag">
<span class="ds-tag ds-tag-size-base ds-tag-medium hc-hashtag">
<nuxt-link :to="hashtagUrl">#{{ id }}</nuxt-link>
</ds-tag>
</span>
</template>
<script>

View File

@ -1,14 +1,14 @@
<template>
<ds-container
class="main-navigation-container"
<div
class="ds-container ds-container-x-large main-navigation-container"
:class="{ 'hide-navbar': hideNavbar }"
id="navbar"
>
<div>
<!-- header menu -->
<ds-flex v-if="!showMobileMenu" class="main-navigation-flex">
<div v-if="!showMobileMenu" class="ds-flex main-navigation-flex">
<!-- logo -->
<ds-flex-item class="logo-wrapper" :width="{ base: 'auto' }">
<div class="ds-flex-item logo-wrapper" style="flex: 0 0 auto">
<a
v-if="LOGOS.LOGO_HEADER_CLICK.externalLink"
:href="LOGOS.LOGO_HEADER_CLICK.externalLink.url"
@ -23,47 +23,47 @@
>
<logo logoType="header" />
</nuxt-link>
</ds-flex-item>
</div>
<!-- dynamic brand menus -->
<ds-flex-item
<div
v-for="item in menu"
:key="item.name"
class="branding-menu"
:width="{ base: 'auto' }"
style="margin-right: 20px"
class="ds-flex-item branding-menu"
style="flex: 0 0 auto; margin-right: 20px"
>
<a v-if="item.url" :href="item.url" :target="item.target">
<ds-text size="large" bold>
<p class="ds-text ds-text-size-large ds-text-bold">
{{ $t(item.nameIdent) }}
</ds-text>
</p>
</a>
<nuxt-link v-else :to="item.path">
<ds-text size="large" bold>
<p class="ds-text ds-text-size-large ds-text-bold">
{{ $t(item.nameIdent) }}
</ds-text>
</p>
</nuxt-link>
</ds-flex-item>
</div>
<!-- search field -->
<ds-flex-item
<div
v-if="isLoggedIn"
id="nav-search-box"
class="header-search"
:width="{ base: 'auto' }"
class="ds-flex-item header-search"
style="flex: 0 0 auto"
>
<search-field />
</ds-flex-item>
</div>
<!-- filter menu -->
<!-- TODO: Filter is only visible on index -->
<ds-flex-item
<div
v-if="isLoggedIn && SHOW_CONTENT_FILTER_HEADER_MENU"
class="ds-flex-item"
style="flex-grow: 0; flex-basis: auto"
>
<client-only>
<filter-menu v-show="showFilterMenuDropdown" />
</client-only>
</ds-flex-item>
</div>
<!-- right symbols -->
<ds-flex-item style="flex: none">
<div class="ds-flex-item" style="flex: none">
<div class="main-navigation-right" style="flex-basis: auto">
<!-- locale switch -->
<locale-switch class="topbar-locale-switch" placement="top" offset="8" />
@ -131,14 +131,17 @@
</client-only>
</template>
</div>
</ds-flex-item>
</ds-flex>
</div>
</div>
<!-- mobile header menu -->
<div v-else class="mobil-header-box">
<!-- logo, hamburger-->
<ds-flex style="align-items: center">
<ds-flex-item :width="{ base: LOGOS.LOGO_HEADER_WIDTH }" class="logo-container">
<div class="ds-flex" style="align-items: center">
<div
class="ds-flex-item logo-container"
:style="{ flex: '0 0 ' + LOGOS.LOGO_HEADER_WIDTH, width: LOGOS.LOGO_HEADER_WIDTH }"
>
<div @click="toggleMobileMenu ? toggleMobileMenuView() : ''">
<a
v-if="LOGOS.LOGO_HEADER_CLICK.externalLink"
@ -155,10 +158,10 @@
<logo logoType="header" />
</nuxt-link>
</div>
</ds-flex-item>
</div>
<!-- mobile hamburger menu -->
<ds-flex-item class="mobile-hamburger-menu">
<div class="ds-flex-item mobile-hamburger-menu">
<client-only>
<!-- chat menu -->
<div>
@ -182,52 +185,56 @@
<os-icon :icon="icons.bars" />
</template>
</os-button>
</ds-flex-item>
</ds-flex>
</div>
</div>
<!-- search, filter -->
<ds-flex class="mobile-menu">
<div class="ds-flex mobile-menu">
<!-- search field mobile -->
<ds-flex-item
<div
v-if="isLoggedIn"
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="padding: 20px"
>
<search-field />
</ds-flex-item>
</div>
<!-- filter menu mobile -->
<ds-flex-item
<div
v-if="isLoggedIn"
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="flex-grow: 0; flex-basis: auto; padding: 20px 0"
>
<client-only>
<filter-menu v-if="showFilterMenuDropdown && SHOW_CONTENT_FILTER_HEADER_MENU" />
</client-only>
</ds-flex-item>
</ds-flex>
</div>
</div>
<!-- right symbols -->
<ds-flex style="margin: 0 20px">
<div class="ds-flex" style="margin: 0 20px">
<!-- locale switch mobile -->
<ds-flex-item :class="{ 'hide-mobile-menu': !toggleMobileMenu }">
<div class="ds-flex-item" :class="{ 'hide-mobile-menu': !toggleMobileMenu }">
<locale-switch
class="topbar-locale-switch topbar-locale-switch-mobile"
placement="top"
offset="8"
/>
</ds-flex-item>
</div>
<!-- invite button mobile -->
<ds-flex-item
<div
v-if="inviteRegistration"
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="text-align: center"
>
<client-only>
<invite-button placement="top" />
</client-only>
</ds-flex-item>
</div>
<!-- group button -->
<ds-flex-item
<div
v-if="SHOW_GROUP_BUTTON_IN_HEADER"
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="text-align: center"
>
@ -251,10 +258,11 @@
</os-button>
</div>
</client-only>
</ds-flex-item>
</div>
<!-- map button -->
<ds-flex-item
<div
v-if="!isEmpty(this.$env.MAPBOX_TOKEN)"
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="text-align: center"
>
@ -279,10 +287,11 @@
</os-button>
</div>
</client-only>
</ds-flex-item>
</div>
<!-- custom button -->
<ds-flex-item
<div
v-if="!isEmpty(customButton)"
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="text-align: center"
>
@ -291,14 +300,18 @@
<custom-button :settings="customButton" />
</div>
</client-only>
</ds-flex-item>
</div>
<!-- avatar menu mobile -->
<ds-flex-item :class="{ 'hide-mobile-menu': !toggleMobileMenu }" style="text-align: end">
<div
class="ds-flex-item"
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
style="text-align: end"
>
<client-only>
<avatar-menu placement="top" @toggle-Mobile-Menu-view="toggleMobileMenuView" />
</client-only>
</ds-flex-item>
</ds-flex>
</div>
</div>
<div :class="{ 'hide-mobile-menu': !toggleMobileMenu }" class="mobile-menu footer-mobile">
<!-- dynamic branding menus -->
<ul v-if="isHeaderMenu" class="dynamic-branding-mobil">
@ -309,15 +322,15 @@
:target="item.target"
@click="toggleMobileMenuView"
>
<ds-text size="large" bold>
<p class="ds-text ds-text-size-large ds-text-bold">
{{ $t(item.nameIdent) }}
</ds-text>
</p>
</a>
<nuxt-link v-else :to="item.path">
<div @click="toggleMobileMenuView">
<ds-text size="large" bold>
<p class="ds-text ds-text-size-large ds-text-bold">
{{ $t(item.nameIdent) }}
</ds-text>
</p>
</div>
</nuxt-link>
</li>
@ -338,7 +351,7 @@
</div>
</div>
</div>
</ds-container>
</div>
</template>
<script>

View File

@ -1,5 +1,8 @@
<template>
<ds-text class="location-teaser" align="left" color="soft" :size="size">
<p
class="ds-text ds-text-left ds-text-soft location-teaser"
:class="size && 'ds-text-size-' + size"
>
<os-icon :icon="icons.mapMarker" data-test="map-marker" />
<span v-if="venue">{{ venue }}</span>
<span v-if="venue">&nbsp;&mdash;&nbsp;</span>
@ -9,7 +12,7 @@
<span v-else>
{{ $t('post.viewEvent.eventIsOnline') }}
</span>
</ds-text>
</p>
</template>
<script>

View File

@ -1,9 +1,9 @@
<template>
<ds-modal :title="title" :is-open="isOpen" @cancel="cancel" data-test="confirm-modal">
<transition name="ds-transition-fade">
<ds-flex v-if="success" class="hc-modal-success" centered>
<div v-if="success" class="ds-flex ds-flex-centered hc-modal-success">
<sweetalert-icon icon="success" />
</ds-flex>
</div>
</transition>
<!-- eslint-disable-next-line vue/no-v-html -->

View File

@ -1,39 +1,39 @@
<template>
<ds-modal class="delete-user-modal" :title="title" :is-open="isOpen" @cancel="cancel">
<transition name="ds-transition-fade">
<ds-flex v-if="success" class="hc-modal-success" centered>
<div v-if="success" class="ds-flex ds-flex-centered hc-modal-success">
<sweetalert-icon icon="success" />
</ds-flex>
</div>
</transition>
<div>
<ds-section>
<ds-flex>
<ds-flex-item width="50%">
<section class="ds-section">
<div class="ds-flex">
<div style="flex: 0 0 50%; width: 50%">
<user-teaser :user="userdata" />
</ds-flex-item>
<ds-flex-item width="20%">
<ds-text size="small">
</div>
<div style="flex: 0 0 20%; width: 20%">
<p class="ds-text ds-text-size-small">
<span class="bold">{{ $t('modals.deleteUser.created') }}</span>
<br />
<date-time :date-time="userdata.createdAt" />
</ds-text>
</ds-flex-item>
<ds-flex-item width="15%">
<ds-text size="small">
</p>
</div>
<div style="flex: 0 0 15%; width: 15%">
<p class="ds-text ds-text-size-small">
<span class="bold">{{ $t('common.post', null, userdata.contributionsCount) }}</span>
<br />
{{ userdata.contributionsCount }}
</ds-text>
</ds-flex-item>
<ds-flex-item width="15%">
<ds-text size="small">
</p>
</div>
<div style="flex: 0 0 15%; width: 15%">
<p class="ds-text ds-text-size-small">
<span class="bold">{{ $t('common.comment', null, userdata.commentedCount) }}</span>
<br />
{{ userdata.commentedCount }}
</ds-text>
</ds-flex-item>
</ds-flex>
</ds-section>
</p>
</div>
</div>
</section>
</div>
<template #footer>

View File

@ -1,9 +1,9 @@
<template>
<ds-modal class="report-modal" :title="title" :is-open="isOpen" @cancel="cancel">
<transition name="ds-transition-fade">
<ds-flex v-if="success" class="hc-modal-success" centered>
<div v-if="success" class="ds-flex ds-flex-centered hc-modal-success">
<sweetalert-icon icon="success" />
</ds-flex>
</div>
</transition>
<!-- eslint-disable-next-line vue/no-v-html -->
@ -27,7 +27,7 @@
<small class="smallTag">
{{ form.reasonDescription.length }}/{{ formSchema.reasonDescription.max }}
</small>
<ds-space />
<div class="ds-mb-large"></div>
<template #footer>
<os-button class="cancel" variant="primary" appearance="outline" @click="cancel">
<template #icon>

View File

@ -43,8 +43,8 @@
</os-button>
</template>
<template #popover="{ closeMenu }">
<ds-flex class="notifications-link-container">
<ds-flex-item>
<div class="ds-flex notifications-link-container">
<div class="ds-flex-item">
<os-button
as="nuxt-link"
:to="{ name: 'notifications' }"
@ -67,8 +67,8 @@
</template>
{{ $t('notifications.markAllAsRead') }}
</os-button>
</ds-flex-item>
</ds-flex>
</div>
</div>
<div class="notifications-menu-popover">
<notifications-table
@markNotificationAsRead="markAsReadAndCloseMenu($event, closeMenu)"

View File

@ -16,8 +16,8 @@
>
<ds-grid>
<ds-grid-item>
<ds-flex class="user-section">
<ds-flex-item>
<div class="ds-flex user-section">
<div class="ds-flex-item">
<user-teaser
:user="
isGroup(notification.from) ? notification.relatedUser : notification.from.author
@ -28,8 +28,8 @@
:injected-date="true"
:show-popover="showPopover"
/>
</ds-flex-item>
</ds-flex>
</div>
</div>
</ds-grid-item>
<ds-grid-item>
<div class="notification-container">

View File

@ -23,7 +23,7 @@
:label="$t('settings.security.change-password.label-new-password-confirm')"
/>
<password-strength :password="formData.password" />
<ds-space margin-top="base">
<div class="ds-mt-base ds-mb-large">
<os-button
variant="primary"
appearance="filled"
@ -36,7 +36,7 @@
</template>
{{ $t('settings.security.change-password.button') }}
</os-button>
</ds-space>
</div>
</template>
</ds-form>
</template>

View File

@ -1,5 +1,5 @@
<template>
<ds-space margin-top="base" margin-bottom="xxx-small">
<div class="ds-mt-base ds-mb-xxx-small">
<ds-form
v-if="!changePasswordResult"
v-model="formData"
@ -23,7 +23,7 @@
:label="$t('settings.security.change-password.label-new-password-confirm')"
/>
<password-strength :password="formData.password" />
<ds-space margin-top="base" margin-bottom="xxx-small">
<div class="ds-mt-base ds-mb-xxx-small">
<os-button
variant="primary"
appearance="filled"
@ -36,37 +36,35 @@
</template>
{{ $t('settings.security.change-password.button') }}
</os-button>
</ds-space>
</div>
</template>
</ds-form>
<ds-space v-else>
<div v-else class="ds-mb-large">
<template v-if="changePasswordResult === 'success'">
<transition name="ds-transition-fade">
<sweetalert-icon icon="success" />
</transition>
<ds-text>
<p class="ds-text">
{{ $t('components.password-reset.change-password.success') }}
</ds-text>
</p>
</template>
<template v-else>
<transition name="ds-transition-fade">
<sweetalert-icon icon="error" />
</transition>
<ds-text>
<p>
<p class="ds-text">
{{ $t(`components.password-reset.change-password.error`) }}
</p>
<p>
<p class="ds-text">
{{ $t('components.password-reset.change-password.help') }}
</p>
<p>
<p class="ds-text">
<a :href="'mailto:' + supportEmail">{{ supportEmail }}</a>
</p>
</ds-text>
</template>
<slot></slot>
</ds-space>
</ds-space>
</div>
</div>
</template>
<script>

View File

@ -7,7 +7,7 @@
:schema="formSchema"
@submit="handleSubmit"
>
<ds-space margin="small">
<div class="ds-my-small">
<ds-input
:placeholder="$t('login.email')"
type="email"
@ -16,10 +16,12 @@
name="email"
icon="envelope"
/>
</ds-space>
<ds-space margin-botton="large">
<ds-text align="left">{{ $t('components.password-reset.request.form.description') }}</ds-text>
</ds-space>
</div>
<div class="ds-mb-large">
<p class="ds-text ds-text-left">
{{ $t('components.password-reset.request.form.description') }}
</p>
</div>
<os-button
variant="primary"
appearance="filled"
@ -33,11 +35,11 @@
</ds-form>
<div v-else>
<transition name="ds-transition-fade">
<ds-flex centered>
<div class="ds-flex ds-flex-centered">
<sweetalert-icon icon="info" />
</ds-flex>
</div>
</transition>
<ds-text v-html="submitMessage" align="left" />
<p class="ds-text ds-text-left" v-html="submitMessage" />
</div>
</template>

View File

@ -26,11 +26,7 @@
</client-only>
<h2 class="title hyphenate-text">{{ post.title }}</h2>
<client-only>
<ds-space
v-if="post && post.postType[0] === 'Event'"
margin-bottom="small"
style="padding: 5px"
>
<div v-if="post && post.postType[0] === 'Event'" class="ds-mb-small" style="padding: 5px">
<location-teaser
class="event-info"
size="base"
@ -44,7 +40,7 @@
:startDate="post.eventStart"
:endDate="post.eventEnd"
/>
</ds-space>
</div>
</client-only>
<!-- TODO: replace editor content with tiptap render view -->
<!-- eslint-disable-next-line vue/no-v-html -->

View File

@ -1,5 +1,5 @@
<template>
<ds-text>
<p class="ds-text">
<b v-if="emailAsString.length > 0">
{{ emailAsString }}
<b v-if="!isEmailFormat" class="email-warning">
@ -9,7 +9,7 @@
<b v-else class="email-warning">
{{ $t('components.registration.email-display.warningUndef') }}
</b>
</ds-text>
</p>
</template>
<script>

View File

@ -3,26 +3,26 @@
<transition name="ds-transition-fade">
<sweetalert-icon icon="success" />
</transition>
<ds-text align="center" bold color="success">
<p class="ds-text ds-text-center ds-text-bold ds-text-success">
{{ $t('components.registration.create-user-account.success') }}
</ds-text>
<ds-space margin="xxx-small" />
</p>
<div class="ds-my-xxx-small"></div>
</div>
<div v-else-if="response === 'error'">
<transition name="ds-transition-fade">
<sweetalert-icon icon="error" />
</transition>
<ds-text align="center" bold color="danger">
<p class="ds-text ds-text-center ds-text-bold ds-text-danger">
{{ $t('components.registration.create-user-account.error') }}
</ds-text>
<ds-text align="center">
</p>
<p class="ds-text ds-text-center">
{{ $t('components.registration.create-user-account.help') }}
<a :href="'mailto:' + supportEmail">{{ supportEmail }}</a>
</ds-text>
<ds-space centered>
</p>
<div class="ds-mb-large ds-space-centered">
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</ds-space>
<ds-space margin="xxx-small" />
</div>
<div class="ds-my-xxx-small"></div>
</div>
<div v-else class="create-account-card">
<ds-form
@ -150,7 +150,7 @@
</div>
</div>
</template>
<ds-space margin="xxx-small" />
<div class="ds-my-xxx-small"></div>
</ds-form>
</div>
</template>

View File

@ -6,18 +6,23 @@
@input="handleInput"
@input-valid="handleInputValid"
>
<ds-text>
<p class="ds-text">
{{ $t('components.registration.signup.form.description') }}
</ds-text>
</p>
<ds-input :placeholder="$t('login.email')" type="email" id="email" model="email" name="email" />
<slot></slot>
<ds-text v-if="sliderData.collectedInputData.emailSend">
<input id="checkbox" type="checkbox" v-model="sendEmailAgain" :checked="sendEmailAgain" />
<label for="checkbox0">
<p class="ds-text" v-if="sliderData.collectedInputData.emailSend">
<input
id="sendEmailAgain"
type="checkbox"
v-model="sendEmailAgain"
:checked="sendEmailAgain"
/>
<label for="sendEmailAgain">
{{ $t('components.registration.email.form.sendEmailAgain') }}
</label>
</ds-text>
<ds-space margin="xxx-small" />
</p>
<div class="ds-my-xxx-small"></div>
</ds-form>
</template>

View File

@ -14,9 +14,9 @@
name="inviteCode"
id="inviteCode"
/>
<ds-text v-if="!validInput">
<p class="ds-text" v-if="!validInput">
{{ $t('components.registration.invite-code.form.description') }}
</ds-text>
</p>
<div class="invitation-info" v-if="invitedBy">
<profile-avatar :profile="invitedBy" size="small" />
<span v-if="invitedTo && invitedTo.groupType === 'hidden'">
@ -39,7 +39,7 @@
</span>
</div>
<slot></slot>
<ds-space margin="xxx-small" />
<div class="ds-my-xxx-small"></div>
</ds-form>
</template>

View File

@ -1,9 +1,9 @@
<template>
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<hc-empty icon="events" :message="$t('components.registration.signup.unavailable')" />
<slot></slot>
<ds-space margin="xxx-small" />
</ds-space>
<div class="ds-my-xxx-small"></div>
</div>
</template>
<script>

View File

@ -14,11 +14,11 @@
name="nonce"
id="nonce"
/>
<ds-text>
<p class="ds-text">
{{ $t('components.registration.email-nonce.form.description') }}
</ds-text>
</p>
<slot></slot>
<ds-space margin="xxx-small" />
<div class="ds-my-xxx-small"></div>
</ds-form>
</template>

View File

@ -1,5 +1,5 @@
<template>
<ds-space v-if="!data && !error" margin="large">
<div v-if="!data && !error" class="ds-my-large">
<ds-form
@input="handleInput"
@input-valid="handleInputValid"
@ -14,15 +14,15 @@
: $t('components.registration.signup.title', metadata)
}}
</h1>
<ds-space margin-botton="large">
<ds-text>
<div class="ds-mb-large">
<p class="ds-text">
{{
invitation
? $t('profile.invites.description')
: $t('components.registration.signup.form.description')
}}
</ds-text>
</ds-space>
</p>
</div>
<ds-input
:placeholder="invitation ? $t('profile.invites.emailPlaceholder') : $t('login.email')"
type="email"
@ -41,22 +41,22 @@
</os-button>
<slot></slot>
</ds-form>
</ds-space>
<div v-else margin="large">
</div>
<div v-else class="ds-my-large">
<template v-if="!error">
<transition name="ds-transition-fade">
<sweetalert-icon icon="info" />
</transition>
<ds-text align="center" v-html="submitMessage" />
<p class="ds-text ds-text-center" v-html="submitMessage" />
</template>
<template v-else>
<transition name="ds-transition-fade">
<sweetalert-icon icon="error" />
</transition>
<ds-text align="center">{{ error.message }}</ds-text>
<ds-space centered class="space-top">
<p class="ds-text ds-text-center">{{ error.message }}</p>
<div class="ds-mb-large ds-space-centered space-top">
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</ds-space>
</div>
</template>
</div>
</template>
@ -143,7 +143,7 @@ export default {
},
}
</script>
<style>
<style scoped>
.space-top {
margin-top: 6ex;
}

View File

@ -2,7 +2,6 @@ import { mount } from '@vue/test-utils'
import SocialMedia from './SocialMedia.vue'
const stubs = {
'ds-space': true,
'ds-text': true,
}

View File

@ -1,21 +1,21 @@
<template>
<ds-space v-if="user.socialMedia && user.socialMedia.length" margin="large">
<div v-if="user.socialMedia && user.socialMedia.length" class="ds-my-large">
<os-card class="social-media-bc">
<ds-space margin="x-small">
<ds-text tag="h5" color="soft" data-test="social-media-list-headline">
<div class="ds-my-x-small">
<h5 class="ds-text ds-text-soft" data-test="social-media-list-headline">
{{ $t('profile.socialMedia') }} {{ userName | truncate(15) }}?
</ds-text>
</h5>
<template>
<ds-space v-for="link in socialMediaLinks()" :key="link.id" margin="x-small">
<div v-for="link in socialMediaLinks()" :key="link.url" class="ds-my-x-small">
<a :href="link.url" target="_blank">
<img :src="link.favicon" alt="Link:" height="22" width="22" />
{{ link.username }}
</a>
</ds-space>
</div>
</template>
</ds-space>
</div>
</os-card>
</ds-space>
</div>
</template>
<script>

View File

@ -1,11 +1,11 @@
<template>
<div>
<ds-space margin="small">
<ds-heading v-if="pageParams.internalPage.headlineIdent !== null" tag="h2">
<div class="ds-my-small">
<h2 v-if="pageParams.internalPage.headlineIdent !== null" class="ds-heading ds-heading-h2">
{{ $t(pageParams.internalPage.headlineIdent) }}
</ds-heading>
</ds-space>
<ds-container v-if="pageParams.internalPage.hasContainer">
</h2>
</div>
<div class="ds-container ds-container-x-large" v-if="pageParams.internalPage.hasContainer">
<div v-if="!pageParams.internalPage.hasBaseCard">
<br />
<div v-html="$t(pageParams.internalPage.htmlIdent)" />
@ -13,7 +13,7 @@
<os-card v-else>
<div v-html="$t(pageParams.internalPage.htmlIdent)" />
</os-card>
</ds-container>
</div>
<div v-else-if="!pageParams.internalPage.hasBaseCard">
<br />
<div v-html="$t(pageParams.internalPage.htmlIdent)" />

View File

@ -7,19 +7,19 @@
@submit="handleSubmitItem"
>
<div v-if="isEditing">
<ds-space margin="base">
<ds-heading tag="h5">
<div class="ds-my-base">
<h5 class="ds-heading ds-heading-h5">
{{ isCreation ? texts.addNew : texts.edit + ' — ' + editingItem[namePropertyKey] }}
</ds-heading>
</ds-space>
<ds-space v-if="items" margin-top="base">
</h5>
</div>
<div v-if="items" class="ds-mt-base ds-mb-large">
<slot name="edit-item" />
</ds-space>
</div>
</div>
<div v-else>
<ds-space v-if="items" margin-top="base">
<ds-list>
<ds-list-item v-for="item in items" :key="item.id" class="list-item--high">
<div v-if="items" class="ds-mt-base ds-mb-large">
<ul class="ds-list">
<li v-for="item in items" :key="item.id" class="ds-list-item list-item--high">
<template>
<slot name="list-item" :item="item" />
<span class="divider">|</span>
@ -50,13 +50,12 @@
</template>
</os-button>
</template>
</ds-list-item>
</ds-list>
</ds-space>
</li>
</ul>
</div>
</div>
<ds-space margin-top="base">
<ds-space margin-top="base">
<div class="ds-mt-base ds-mb-large">
<os-button
variant="primary"
appearance="filled"
@ -76,8 +75,7 @@
>
{{ $t('actions.cancel') }}
</os-button>
</ds-space>
</ds-space>
</div>
</ds-form>
</template>
@ -216,13 +214,7 @@ export default {
}
.list-item--high {
.ds-list-item-prefix {
align-self: center;
}
.ds-list-item-content {
display: flex;
align-items: center;
}
}
</style>

View File

@ -1,15 +1,15 @@
<template>
<div id="search-results" class="search-results">
<ds-flex-item :width="{ base: '100%', sm: 3, md: 5, lg: 3 }">
<div class="search-results__content">
<masonry-grid>
<!-- search text -->
<ds-grid-item class="grid-total-search-results" :row-span="1" column-span="fullWidth">
<ds-space margin-bottom="xxx-small" margin-top="xxx-small" centered>
<ds-text class="total-search-results">
<div class="ds-mb-xxx-small ds-mt-xxx-small ds-space-centered">
<p class="ds-text total-search-results">
{{ $t('search.for') }}
<strong>{{ '"' + (search || '') + '"' }}</strong>
</ds-text>
</ds-space>
</p>
</div>
</ds-grid-item>
<!-- tabs -->
@ -20,7 +20,7 @@
<template v-if="!(!activeResourceCount || searchCount === 0)">
<!-- pagination buttons -->
<ds-grid-item v-if="activeResourceCount > pageSize" :row-span="2" column-span="fullWidth">
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<pagination-buttons
:hasNext="hasNext"
:showPageCounter="true"
@ -32,7 +32,7 @@
@back="previousResults"
@next="nextResults"
/>
</ds-space>
</div>
</ds-grid-item>
<!-- posts -->
@ -86,7 +86,7 @@
<!-- pagination buttons -->
<ds-grid-item v-if="activeResourceCount > pageSize" :row-span="2" column-span="fullWidth">
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<pagination-buttons
:hasNext="hasNext"
:hasPrevious="hasPrevious"
@ -99,18 +99,18 @@
@back="previousResults"
@next="nextResults"
/>
</ds-space>
</div>
</ds-grid-item>
</template>
<!-- no results -->
<ds-grid-item v-else :row-span="7" column-span="fullWidth">
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<hc-empty icon="tasks" :message="$t('search.no-results', { search })" />
</ds-space>
</div>
</ds-grid-item>
</masonry-grid>
</ds-flex-item>
</div>
</div>
</template>
@ -409,6 +409,25 @@ export default {
</script>
<style lang="scss">
.search-results__content {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-small} {
.search-results__content {
flex: 3 0 0;
}
}
@media #{$media-query-medium} {
.search-results__content {
flex: 5 0 0;
}
}
@media #{$media-query-large} {
.search-results__content {
flex: 3 0 0;
}
}
.search-results {
> .results {
padding: $space-small;

View File

@ -14,13 +14,13 @@
:data-test="tab.type + '-tab'"
>
<a :data-test="tab.type + '-tab-click'" @click="switchTab(tab)">
<ds-space margin="small">
<div class="ds-my-small">
<client-only :placeholder="$t('client-only.loading')">
<ds-number :label="tab.title">
<hc-count-to slot="count" :end-val="tab.count" />
</ds-number>
</client-only>
</ds-space>
</div>
</a>
</li>
</ul>

View File

@ -179,9 +179,9 @@ storiesOf('TabNavigator', module)
<!-- no results -->
<ds-grid-item v-else :row-span="7" column-span="fullWidth">
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<hc-empty icon="tasks" :message="$t('search.no-results', { search })" />
</ds-space>
</div>
</ds-grid-item>
</masonry-grid>
</ds-flex-item>

View File

@ -15,9 +15,9 @@
/>
</template>
<template #reportedOn="scope">
<ds-text size="small">
<p class="ds-text ds-text-size-small">
<date-time :date-time="scope.row.createdAt" data-test="filed-date" />
</ds-text>
</p>
</template>
<template #reasonCategory="scope">
{{ $t('report.reason.category.options.' + scope.row.reasonCategory) }}

View File

@ -8,7 +8,6 @@ const localVue = global.localVue
const stubs = {
'client-only': true,
'ds-space': true,
'nuxt-link': true,
}

View File

@ -1,7 +1,7 @@
<template>
<ds-heading soft size="h5" class="search-heading">
<h5 class="ds-heading ds-heading-h5 ds-heading-soft search-heading">
{{ $t(`search.heading.${resourceType}`, {}, 2) }}
</ds-heading>
</h5>
</template>
<script>
export default {

View File

@ -1,15 +1,18 @@
<template>
<div class="layout-blank">
<div class="main-navigation">
<ds-container width="x-large" class="main-navigation-container" style="padding: 10px 10px">
<ds-flex class="main-navigation-flex" centered>
<ds-flex-item width="5.5%" />
<ds-flex-item style="flex-grow: 1" width="20%">
<div
class="ds-container ds-container-x-large main-navigation-container"
style="padding: 10px 10px"
>
<div class="ds-flex ds-flex-centered main-navigation-flex">
<div style="flex: 0 0 5.5%; width: 5.5%"></div>
<div style="flex: 0 0 20%; width: 20%; flex-grow: 1">
<a @click="redirectToRoot">
<logo logoType="header" />
</a>
</ds-flex-item>
<ds-flex-item width="20%" style="flex-grow: 0">
</div>
<div style="flex: 0 0 20%; width: 20%; flex-grow: 0">
<div class="main-navigation-right" style="flex-basis: auto">
<locale-switch class="topbar-locale-switch" placement="top" offset="8" />
<template v-if="!isLoggedIn">
@ -18,15 +21,15 @@
</client-only>
</template>
</div>
</ds-flex-item>
</ds-flex>
</ds-container>
</div>
<ds-container>
</div>
</div>
</div>
<div class="ds-container ds-container-x-large">
<div class="content">
<nuxt />
</div>
</ds-container>
</div>
<page-footer></page-footer>
<div id="overlay" />
</div>

View File

@ -1,10 +1,10 @@
<template>
<div class="layout-blank">
<ds-container>
<div class="ds-container ds-container-x-large">
<div>
<nuxt />
</div>
</ds-container>
</div>
<div id="overlay" />
</div>
</template>

View File

@ -3,11 +3,11 @@
<div class="main-navigation">
<header-menu :showMobileMenu="isMobile" />
</div>
<ds-container>
<div class="ds-container ds-container-x-large">
<div class="main-container">
<nuxt />
</div>
</ds-container>
</div>
<page-footer v-if="!isMobile" />
<div id="overlay" />
<client-only>
@ -63,7 +63,7 @@ export default {
}
.main-container {
padding-top: 6rem;
padding-bottom: 5rem;
padding-bottom: 8rem;
}
.chat-modul {

View File

@ -1,11 +1,11 @@
<template>
<div class="layout-blank">
<div class="layout-content">
<ds-container>
<div class="ds-container ds-container-x-large">
<div>
<nuxt />
</div>
</ds-container>
</div>
</div>
<page-footer :is-sticky="false" />
<div id="overlay" />

View File

@ -704,6 +704,7 @@
"failure": "Fehlerhafte E-Mail-Adresse oder Passwort.",
"forgotPassword": "Passwort vergessen?",
"hello": "Hallo",
"loggingOut": "Abmeldung läuft …",
"login": "Anmelden",
"logout": "Abmelden",
"moreInfo": "Was ist {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": "Incorrect email address or password.",
"forgotPassword": "Forgot Password?",
"hello": "Hello",
"loggingOut": "Logging out…",
"login": "Login",
"logout": "Logout",
"moreInfo": "What is {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": "Dirección de correo electrónico o contraseña incorrecta.",
"forgotPassword": "¿Olvidó su contraseña?",
"hello": "Hola",
"loggingOut": "Cerrando sesión …",
"login": "Iniciar sesión",
"logout": "Cierre de sesión",
"moreInfo": "¿Qué es {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": "Adresse mail ou mot de passe incorrect.",
"forgotPassword": "Mot de passe oublié?",
"hello": "Bonjour",
"loggingOut": "Déconnexion en cours …",
"login": "Connexion",
"logout": "Déconnexion",
"moreInfo": "Qu'est-ce que {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": null,
"forgotPassword": null,
"hello": "Ciao",
"loggingOut": "Disconnessione in corso …",
"login": "Accesso",
"logout": "Logout",
"moreInfo": "Che cosa è {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": null,
"forgotPassword": null,
"hello": "Hallo",
"loggingOut": "Uitloggen …",
"login": "Inloggen",
"logout": "Uitloggen",
"moreInfo": "Wat is {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": null,
"forgotPassword": "Zapomniałeś hasła?",
"hello": "Cześć",
"loggingOut": "Wylogowywanie …",
"login": "Logowanie",
"logout": "Wyloguj się",
"moreInfo": "Co to jest {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": "Endereço de e-mail ou senha incorretos.",
"forgotPassword": "Esqueceu a sua senha?",
"hello": "Olá",
"loggingOut": "A terminar sessão …",
"login": "Entrar",
"logout": "Sair",
"moreInfo": "O que é a {APPLICATION_NAME}?",

View File

@ -704,6 +704,7 @@
"failure": "Неверный адрес электронной почты или пароль.",
"forgotPassword": "Забыли пароль?",
"hello": "Здравствуйте",
"loggingOut": "Выход из системы …",
"login": "Вход",
"logout": "Выйти",
"moreInfo": "Что такое {APPLICATION_NAME}?",

View File

@ -1,13 +1,13 @@
<template>
<transition name="fade" appear>
<ds-container width="medium">
<div class="ds-container ds-container-medium">
<os-card>
<ds-space>
<div class="ds-mb-large">
<locale-switch class="login-locale-switch" offset="5" />
</ds-space>
<ds-flex>
<ds-flex-item :width="{ base: '100%', sm: 1, md: 1 }">
<ds-space>
</div>
<div class="ds-flex maintenance-layout">
<div class="maintenance-layout__image">
<div class="ds-mb-large">
<!-- QUESTION: could we have internal page or even all internal pages here as well with PageParamsLink by having the footer underneath? -->
<!-- I tried this out, but only could get the nginx page displayed. I guees the there were nuxt errors, because the nuxt config file 'webapp/maintenance/source/nuxt.config.maintenance.js' would have to be refactored for that as well and may be the missing folder `components/_new/generic/` plays a role, see https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4619 -->
<!-- <page-params-link :pageParams="links.ORGANIZATION" :title="$t('login.moreInfo', metadata)">
@ -19,27 +19,31 @@
:title="$t('login.moreInfo', metadata)"
target="_blank"
> -->
<img class="image" alt="Under maintenance" src="/img/custom/logo-squared.svg" />
<img
class="image"
:alt="$t('maintenance.title', metadata)"
src="/img/custom/logo-squared.svg"
/>
<!-- </a> -->
</ds-space>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: 1, md: 1 }">
<ds-flex-item>
<ds-heading tag="h3">{{ $t('maintenance.title', metadata) }}</ds-heading>
</ds-flex-item>
<ds-flex-item>
<ds-space margin="small">
<ds-text>{{ $t('maintenance.explanation') }}</ds-text>
<ds-text>
</div>
</div>
<div class="maintenance-layout__content">
<div>
<h3 class="ds-heading ds-heading-h3">{{ $t('maintenance.title', metadata) }}</h3>
</div>
<div>
<div class="ds-my-small">
<p class="ds-text">{{ $t('maintenance.explanation') }}</p>
<p class="ds-text">
{{ $t('maintenance.questions') }}
<a :href="'mailto:' + supportEmail">{{ supportEmail }}</a>
</ds-text>
</ds-space>
</ds-flex-item>
</ds-flex-item>
</ds-flex>
</p>
</div>
</div>
</div>
</div>
</os-card>
</ds-container>
</div>
</transition>
</template>
@ -65,9 +69,22 @@ export default {
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.image {
width: 75%;
height: auto;
}
.maintenance-layout__image,
.maintenance-layout__content {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-small} {
.maintenance-layout__image {
flex: 1 0 0;
}
.maintenance-layout__content {
flex: 1 0 0;
}
}
</style>

View File

@ -88,6 +88,8 @@ export default {
'~assets/styles/imports/_branding.scss',
// @ocelot-social/ui CSS variables (loaded before styleguide)
'~assets/_new/styles/ocelot-ui-variables.scss',
// Utility classes replacing ds-* Vue components
'~assets/_new/styles/_ds-compat.scss',
// Note: @ocelot-social/ui/style.css is loaded via plugin after styleguide
],

View File

@ -4,8 +4,7 @@ exports[`_static mount renders 1`] = `
<div>
<div>
<div
class="ds-space"
style="margin-top: 16px; margin-bottom: 16px;"
class="ds-my-small"
>
<h2
class="ds-heading ds-heading-h2"

View File

@ -4,8 +4,7 @@ exports[`settings.vue given badges are disabled renders 1`] = `
<div>
<div>
<div
class="ds-space"
style="margin-top: 16px; margin-bottom: 16px;"
class="ds-my-small"
>
<h1
class="ds-heading ds-heading-h1"
@ -15,13 +14,11 @@ exports[`settings.vue given badges are disabled renders 1`] = `
</div>
<div
class="ds-space"
style="margin-top: 32px; margin-bottom: 32px;"
class="ds-my-large"
/>
<div
class="ds-flex"
style="margin-left: -8px; margin-right: -8px;"
class="ds-flex ds-flex-gap-small"
>
<div
class="menu-container"
@ -210,8 +207,7 @@ exports[`settings.vue given badges are enabled renders 1`] = `
<div>
<div>
<div
class="ds-space"
style="margin-top: 16px; margin-bottom: 16px;"
class="ds-my-small"
>
<h1
class="ds-heading ds-heading-h1"
@ -221,13 +217,11 @@ exports[`settings.vue given badges are enabled renders 1`] = `
</div>
<div
class="ds-space"
style="margin-top: 32px; margin-bottom: 32px;"
class="ds-my-large"
/>
<div
class="ds-flex"
style="margin-left: -8px; margin-right: -8px;"
class="ds-flex ds-flex-gap-small"
>
<div
class="menu-container"

View File

@ -1,16 +1,16 @@
<template>
<div>
<ds-heading tag="h1">{{ $t('admin.name') }}</ds-heading>
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', md: '200px' }">
<h1 class="ds-heading ds-heading-h1">{{ $t('admin.name') }}</h1>
<div class="ds-flex ds-flex-gap-small admin-layout">
<div class="admin-layout__sidebar">
<ds-menu :routes="routes" :is-exact="() => true" />
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', md: 1 }">
</div>
<div class="admin-layout__main">
<transition name="slide-up" appear>
<nuxt-child />
</transition>
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
</template>
@ -69,3 +69,20 @@ export default {
},
}
</script>
<style lang="scss">
.admin-layout__sidebar,
.admin-layout__main {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-medium} {
.admin-layout__sidebar {
flex: 0 0 200px;
width: 200px;
}
.admin-layout__main {
flex: 1 0 0;
}
}
</style>

View File

@ -2,12 +2,12 @@
<os-card>
<h2 class="title">{{ $t('admin.donations.name') }}</h2>
<ds-form v-model="formData" @submit="submit">
<ds-text class="show-donations-checkbox">
<p class="ds-text show-donations-checkbox">
<input id="showDonations" type="checkbox" v-model="showDonations" />
<label for="showDonations">
{{ $t('admin.donations.showDonationsCheckboxLabel') }}
</label>
</ds-text>
</p>
<ds-input
id="donations-goal"
class="donations-data"

View File

@ -6,33 +6,33 @@
</div>
</template>
<template v-else-if="statistics">
<ds-space margin="large">
<ds-flex>
<ds-flex-item
<div class="ds-my-large">
<div class="ds-flex">
<div
v-for="(value, name) in filterStatistics(statistics)"
:key="name"
:width="{ base: '100%', sm: '50%', md: '33%' }"
class="admin-stats__item"
>
<ds-space margin="small">
<div class="ds-my-small">
<ds-number :count="0" :label="$t('admin.dashboard.' + name)" size="x-large" uppercase>
<client-only slot="count">
<hc-count-to :end-val="value" />
</client-only>
</ds-number>
</ds-space>
</ds-flex-item>
</ds-flex>
</ds-space>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<ds-space centered>
<ds-space>
<div class="ds-mb-large ds-space-centered">
<div class="ds-mb-large">
<img :src="errorIconPath" width="40" />
</ds-space>
<ds-text>
</div>
<p class="ds-text">
{{ $t('site.error-occurred') }}
</ds-text>
</ds-space>
</p>
</div>
</template>
</os-card>
</template>
@ -70,3 +70,22 @@ export default {
},
}
</script>
<style lang="scss">
.admin-stats__item {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-small} {
.admin-stats__item {
flex: 0 0 50%;
width: 50%;
}
}
@media #{$media-query-medium} {
.admin-stats__item {
flex: 0 0 33.333%;
width: 33.333%;
}
}
</style>

View File

@ -1,13 +1,13 @@
<template>
<ds-section>
<ds-space>
<ds-heading size="h3">{{ $t('admin.invites.title') }}</ds-heading>
<ds-text>{{ $t('admin.invites.description') }}</ds-text>
</ds-space>
<section class="ds-section">
<div class="ds-mb-large">
<h1 class="ds-heading ds-heading-h3">{{ $t('admin.invites.title') }}</h1>
<p class="ds-text">{{ $t('admin.invites.description') }}</p>
</div>
<os-card>
<signup :invitation="true" />
</os-card>
</ds-section>
</section>
</template>
<script>

View File

@ -7,14 +7,7 @@ exports[`.vue renders 1`] = `
class="ds-section"
>
<div
class="ds-section-content"
>
<div
class="ds-container ds-container-x-large"
>
<div
class="ds-space"
style="margin-bottom: 32px;"
class="ds-mb-large"
>
<h1
class="ds-heading ds-heading-h3"
@ -94,8 +87,6 @@ exports[`.vue renders 1`] = `
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</body>

View File

@ -19,12 +19,10 @@ exports[`Users given badges are disabled renders 1`] = `
novalidate="novalidate"
>
<div
class="ds-flex"
style="margin-left: -8px; margin-right: -8px;"
class="ds-flex ds-flex-gap-small"
>
<div
class="ds-flex-item"
style="flex-basis: 90%; width: 90%; padding-left: 8px; padding-right: 8px; margin-bottom: 16px;"
style="flex: 0 0 90%; width: 90%;"
>
<div
class="ds-form-item ds-input-size-base"
@ -83,8 +81,7 @@ exports[`Users given badges are disabled renders 1`] = `
</div>
<div
class="ds-flex-item"
style="flex-basis: 30px; width: 30px; padding-left: 8px; padding-right: 8px; margin-bottom: 16px;"
style="flex: 0 0 30px; width: 30px;"
>
<button
aria-label="actions.search"
@ -473,12 +470,10 @@ exports[`Users given badges are enabled renders 1`] = `
novalidate="novalidate"
>
<div
class="ds-flex"
style="margin-left: -8px; margin-right: -8px;"
class="ds-flex ds-flex-gap-small"
>
<div
class="ds-flex-item"
style="flex-basis: 90%; width: 90%; padding-left: 8px; padding-right: 8px; margin-bottom: 16px;"
style="flex: 0 0 90%; width: 90%;"
>
<div
class="ds-form-item ds-input-size-base"
@ -537,8 +532,7 @@ exports[`Users given badges are enabled renders 1`] = `
</div>
<div
class="ds-flex-item"
style="flex-basis: 30px; width: 30px; padding-left: 8px; padding-right: 8px; margin-bottom: 16px;"
style="flex: 0 0 30px; width: 30px;"
>
<button
aria-label="actions.search"

View File

@ -1,13 +1,13 @@
<template>
<ds-section>
<ds-space>
<ds-heading size="h3">
<section class="ds-section">
<div class="ds-mb-large">
<h1 class="ds-heading ds-heading-h3">
{{ user && user.name }}
-
{{ $t('admin.badges.title') }}
</ds-heading>
<ds-text>{{ $t('admin.badges.description') }}</ds-text>
</ds-space>
</h1>
<p class="ds-text">{{ $t('admin.badges.description') }}</p>
</div>
<os-card v-if="!isLoadingBadges">
<badges-section
:title="$t('admin.badges.verificationBadges')"
@ -20,7 +20,7 @@
@toggleBadge="toggleBadge"
/>
</os-card>
</ds-section>
</section>
</template>
<script>

View File

@ -3,15 +3,15 @@
<os-card>
<h2 class="title">{{ $t('admin.users.name') }}</h2>
<ds-form v-model="form" @submit="submit">
<ds-flex gutter="small">
<ds-flex-item width="90%">
<div class="ds-flex ds-flex-gap-small">
<div style="flex: 0 0 90%; width: 90%">
<ds-input
model="query"
:placeholder="$t('admin.users.form.placeholder')"
icon="search"
/>
</ds-flex-item>
<ds-flex-item width="30px">
</div>
<div style="flex: 0 0 30px; width: 30px">
<os-button
variant="primary"
appearance="filled"
@ -22,8 +22,8 @@
>
<template #icon><os-icon :icon="icons.search" /></template>
</os-button>
</ds-flex-item>
</ds-flex>
</div>
</div>
</ds-form>
</os-card>
<os-card v-if="User && User.length">
@ -69,7 +69,7 @@
{{ value }}
</option>
</select>
<ds-text v-else>{{ scope.row.role }}</ds-text>
<p class="ds-text" v-else>{{ scope.row.role }}</p>
</template>
</template>
<template #badges="scope">
@ -91,7 +91,7 @@
<pagination-buttons :hasNext="hasNext" :hasPrevious="hasPrevious" @next="next" @back="back" />
</os-card>
<os-card v-else>
<ds-placeholder>{{ $t('admin.users.empty') }}</ds-placeholder>
<div class="ds-placeholder">{{ $t('admin.users.empty') }}</div>
</os-card>
</div>
</template>

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
<template>
<div class="group-profile" v-if="isGroupVisible">
<ds-space />
<ds-flex v-if="group" :width="{ base: '100%' }" gutter="base">
<ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }">
<div class="ds-mb-large"></div>
<div v-if="group" class="ds-flex ds-flex-gap-base group-layout">
<div class="group-layout__sidebar">
<os-card
:class="{ 'disabled-content': group.disabled }"
style="position: relative; height: auto; overflow: visible"
@ -27,15 +27,15 @@
@unmute="unmuteGroup"
/>
</client-only>
<ds-space margin="small">
<div class="ds-my-small">
<!-- group name -->
<ds-heading tag="h3" align="center" no-margin>
<h3 class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin">
{{ groupName }}
</ds-heading>
</h3>
<!-- group slug -->
<ds-text align="center" color="soft">
<p class="ds-text ds-text-center ds-text-soft">
{{ `&${groupSlug}` }}
</ds-text>
</p>
<!-- group location -->
<location-info
v-if="group.location"
@ -44,13 +44,13 @@
size="small"
/>
<!-- group created at -->
<ds-text align="center" color="soft" size="small">
<p class="ds-text ds-text-center ds-text-soft ds-text-size-small">
{{ $t('group.foundation') }} {{ group.createdAt | date('MMMM yyyy') }}
</ds-text>
</ds-space>
<ds-flex v-if="isAllowedSeeingGroupMembers">
</p>
</div>
<div class="ds-flex" v-if="isAllowedSeeingGroupMembers">
<!-- group members count -->
<ds-flex-item v-if="isAllowedSeeingGroupMembers">
<div class="ds-flex-item" v-if="isAllowedSeeingGroupMembers">
<client-only>
<ds-number :label="$t('group.membersCount', {}, groupMembers.length)">
<count-to
@ -60,8 +60,8 @@
/>
</ds-number>
</client-only>
</ds-flex-item>
</ds-flex>
</div>
</div>
<div class="action-buttons">
<os-button
variant="danger"
@ -85,12 +85,12 @@
/>
</div>
<hr />
<ds-space margin-top="small" margin-bottom="small">
<div class="ds-mt-small ds-mb-small">
<!-- group my role in group -->
<template v-if="isGroupMember">
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
<p class="ds-text ds-text-soft ds-text-size-small centered-text hyphenate-text">
{{ $t('group.role') }}
</ds-text>
</p>
<div class="chip" align="center">
<ds-chip color="primary">
{{ group && group.myRole ? $t('group.roles.' + group.myRole) : '' }}
@ -98,18 +98,18 @@
</div>
</template>
<!-- group type -->
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
<p class="ds-text ds-text-soft ds-text-size-small centered-text hyphenate-text">
{{ $t('group.type') }}
</ds-text>
</p>
<div class="chip" align="center">
<ds-chip color="primary">
{{ group && group.groupType ? $t('group.types.' + group.groupType) : '' }}
</ds-chip>
</div>
<!-- group action radius -->
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
<p class="ds-text ds-text-soft ds-text-size-small centered-text hyphenate-text">
{{ $t('group.actionRadius') }}
</ds-text>
</p>
<div class="chip" align="center">
<ds-chip color="primary">
{{
@ -117,15 +117,15 @@
}}
</ds-chip>
</div>
<ds-space margin="x-small" />
</ds-space>
<div class="ds-my-x-small"></div>
</div>
<!-- group categories -->
<template
v-if="categoriesActive && group && group.categories && group.categories.length > 0"
>
<hr />
<ds-space margin-top="small" margin-bottom="small">
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
<div class="ds-mt-small ds-mb-small">
<p class="ds-text ds-text-soft ds-text-size-small centered-text hyphenate-text">
{{
$t(
'group.categories',
@ -133,8 +133,8 @@
group && group.categories ? group.categories.length : 0,
)
}}
</ds-text>
<ds-space margin="xx-small" />
</p>
<div class="ds-my-xx-small"></div>
<div class="categories">
<div
v-for="(category, index) in sortCategories(
@ -151,29 +151,32 @@
placement: 'bottom-start',
}"
/>
<ds-space v-if="index < group.categories.length - 1" margin="xxx-small" />
<div v-if="index < group.categories.length - 1" class="ds-my-xxx-small"></div>
</div>
</div>
</div>
</ds-space>
</template>
<!-- group goal -->
<template v-if="group && group.about">
<hr />
<ds-space margin-top="small" margin-bottom="small">
<ds-text class="centered-text hyphenate-text" color="soft" size="small">
<div class="ds-mt-small ds-mb-small">
<p class="ds-text ds-text-soft ds-text-size-small centered-text hyphenate-text">
{{ $t('group.goal') }}
</ds-text>
<ds-space margin="xx-small" />
</p>
<div class="ds-my-xx-small"></div>
<div class="chip" align="center">
<ds-chip>{{ group ? group.about : '' }}</ds-chip>
</div>
</ds-space>
</div>
</template>
</os-card>
<ds-space />
<ds-heading tag="h3" soft style="text-align: center; margin-bottom: 10px">
<div class="ds-mb-large"></div>
<h3
class="ds-heading ds-heading-h3 ds-heading-soft"
style="text-align: center; margin-bottom: 10px"
>
{{ $t('profile.network.title') }}
</ds-heading>
</h3>
<!-- Group members list -->
<profile-list
:uniqueName="'groupMembersFilter'"
@ -191,11 +194,11 @@
@fetchAllProfiles="fetchAllMembers"
/>
<!-- <social-media :user-name="groupName" :user="user" /> -->
</ds-flex-item>
</div>
<ds-flex-item :width="{ base: '100%', sm: 3, md: 5, lg: 3 }">
<div class="group-layout__main">
<!-- Group description -->
<ds-space>
<div class="ds-mb-large">
<os-card class="group-description">
<!-- TODO: replace editor content with tiptap render view -->
<!-- eslint-disable-next-line vue/no-v-html -->
@ -215,8 +218,8 @@
{{ isDescriptionCollapsed ? $t('comment.show.more') : $t('comment.show.less') }}
</os-button>
</os-card>
</ds-space>
<ds-space v-if="isGroupMemberNonePending" centered>
</div>
<div v-if="isGroupMemberNonePending" class="ds-mb-large ds-space-centered">
<os-button
as="nuxt-link"
:to="{
@ -237,7 +240,7 @@
<os-icon :icon="icons.plus" />
</template>
</os-button>
</ds-space>
</div>
<masonry-grid>
<!-- TapNavigation -->
<!-- <tab-navigation :tabs="tabOptions" :activeTab="tabActive" @switch-tab="handleTab" /> -->
@ -284,8 +287,8 @@
<os-spinner slot="spinner" size="lg" />
</infinite-loading>
</client-only>
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
</template>
@ -652,12 +655,41 @@ export default {
margin-top: -60px;
}
.group-profile {
.ds-flex-item:first-child .group-profile-content-menu {
.group-layout__sidebar .group-profile-content-menu {
position: absolute;
top: $space-x-small;
right: $space-x-small;
}
}
.group-layout__sidebar,
.group-layout__main {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-small} {
.group-layout__sidebar {
flex: 2 0 0;
}
.group-layout__main {
flex: 3 0 0;
}
}
@media #{$media-query-medium} {
.group-layout__sidebar {
flex: 2 0 0;
}
.group-layout__main {
flex: 5 0 0;
}
}
@media #{$media-query-large} {
.group-layout__sidebar {
flex: 1 0 0;
}
.group-layout__main {
flex: 3 0 0;
}
}
.profile-post-add-button {
box-shadow: $box-shadow-x-large;
}

View File

@ -1,23 +1,23 @@
<template>
<div>
<ds-space margin="small">
<ds-heading tag="h1">{{ $t('group.createNewGroup.title') }}</ds-heading>
</ds-space>
<ds-space margin="large" />
<ds-container>
<div class="ds-my-small">
<h1 class="ds-heading ds-heading-h1">{{ $t('group.createNewGroup.title') }}</h1>
</div>
<div class="ds-my-large"></div>
<div class="ds-container ds-container-x-large">
<os-card>
<ds-space margin="large">
<ds-flex :width="{ base: '100%' }" gutter="base">
<ds-flex-item :width="{ base: '100%', md: 5 }">
<ds-container>
<div class="ds-my-large">
<div class="ds-flex ds-flex-gap-base group-create-layout">
<div class="group-create-layout__main">
<div class="ds-container ds-container-x-large">
<group-form @createGroup="createGroup" />
</ds-container>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', md: 1 }">&nbsp;</ds-flex-item>
</ds-flex>
</ds-space>
</div>
</div>
<div class="group-create-layout__aside">&nbsp;</div>
</div>
</div>
</os-card>
</ds-container>
</div>
</div>
</template>
@ -71,3 +71,19 @@ export default {
},
}
</script>
<style lang="scss">
.group-create-layout__main,
.group-create-layout__aside {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-medium} {
.group-create-layout__main {
flex: 5 0 0;
}
.group-create-layout__aside {
flex: 1 0 0;
}
}
</style>

View File

@ -1,25 +1,25 @@
<template>
<div>
<ds-space margin="small">
<ds-heading tag="h1">{{ $t('group.editGroupSettings.title') }}</ds-heading>
<ds-heading tag="h2">
<div class="ds-my-small">
<h1 class="ds-heading ds-heading-h1">{{ $t('group.editGroupSettings.title') }}</h1>
<h2 class="ds-heading ds-heading-h2">
{{ $t('group.editGroupSettings.groupTitle') }}
<nuxt-link :to="{ name: 'groups-id-slug', params: { slug: group.slug, id: group.id } }">
{{ group.name }}
</nuxt-link>
</ds-heading>
</ds-space>
<ds-space margin="large" />
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', md: '200px' }">
</h2>
</div>
<div class="ds-my-large"></div>
<div class="ds-flex ds-flex-gap-small group-edit-layout">
<div class="group-edit-layout__sidebar">
<ds-menu :routes="routes" :is-exact="() => true" />
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', md: 1 }">
</div>
<div class="group-edit-layout__main">
<transition name="slide-up" appear>
<nuxt-child :group="group" @update-invite-codes="updateInviteCodes" />
</transition>
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
</template>
@ -87,3 +87,20 @@ export default {
margin-top: 0;
}
</style>
<style lang="scss">
.group-edit-layout__sidebar,
.group-edit-layout__main {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-medium} {
.group-edit-layout__sidebar {
flex: 0 0 200px;
width: 200px;
}
.group-edit-layout__main {
flex: 1 0 0;
}
}
</style>

View File

@ -13,8 +13,7 @@ exports[`invites.vue renders 1`] = `
</h3>
<div
class="ds-space"
style="margin-top: 32px; margin-bottom: 32px;"
class="ds-my-large"
/>
<div

View File

@ -1,8 +1,8 @@
<template>
<div>
<os-card>
<ds-heading tag="h3">{{ $t('group.general') }}</ds-heading>
<ds-space margin="large" />
<h3 class="ds-heading ds-heading-h3">{{ $t('group.general') }}</h3>
<div class="ds-my-large"></div>
<group-form :group="group" :update="true" @updateGroup="updateGroup" />
</os-card>
</div>

View File

@ -1,8 +1,8 @@
<template>
<div>
<os-card>
<ds-heading tag="h3">{{ $t('invite-codes.group-invite-links') }}</ds-heading>
<ds-space margin="large" />
<h3 class="ds-heading ds-heading-h3">{{ $t('invite-codes.group-invite-links') }}</h3>
<div class="ds-my-large"></div>
<invitation-list
@generate-invite-code="generateGroupInviteCode"
@invalidate-invite-code="invalidateInviteCode"

View File

@ -5,7 +5,7 @@
:groupMembers="groupMembers"
@loadGroupMembers="loadGroupMembers"
/>
<ds-space margin-bottom="small" />
<div class="ds-mb-small"></div>
<os-card>
<group-member
:groupId="group.id"

View File

@ -1,12 +1,12 @@
<template>
<div>
<ds-space margin="small">
<div class="ds-my-small">
<tab-navigation :tabs="tabOptions" :activeTab="tabActive" @switch-tab="handleTab" />
</ds-space>
<ds-space margin="large" />
<ds-space>
</div>
<div class="ds-my-large"></div>
<div class="ds-mb-large">
<!-- create group -->
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<os-button
as="nuxt-link"
:to="{ name: 'groups-create' }"
@ -25,9 +25,9 @@
<os-icon :icon="icons.plus" />
</template>
</os-button>
</ds-space>
</div>
<!-- group list -->
<ds-space centered v-if="showPagination">
<div class="ds-mb-large ds-space-centered" v-if="showPagination">
<pagination-buttons
:hasNext="hasNext"
:showPageCounter="true"
@ -39,9 +39,9 @@
@back="previousResults"
@next="nextResults"
/>
</ds-space>
</div>
<group-list :groups="myGroups" />
<ds-space centered v-if="showPagination">
<div class="ds-mb-large ds-space-centered" v-if="showPagination">
<pagination-buttons
:hasNext="hasNext"
:showPageCounter="true"
@ -53,8 +53,8 @@
@back="previousResults"
@next="nextResults"
/>
</ds-space>
</ds-space>
</div>
</div>
</div>
</template>

View File

@ -138,8 +138,8 @@
<template v-else>
<ds-grid-item :row-span="2" column-span="fullWidth">
<hc-empty icon="docs" />
<ds-text align="center">{{ $t('index.no-results') }}</ds-text>
<ds-text align="center">{{ $t('index.change-filter-settings') }}</ds-text>
<p class="ds-text ds-text-center">{{ $t('index.no-results') }}</p>
<p class="ds-text ds-text-center">{{ $t('index.change-filter-settings') }}</p>
</ds-grid-item>
</template>
</masonry-grid>

View File

@ -1,16 +1,16 @@
<template>
<ds-container width="small">
<ds-flex>
<ds-flex-item :width="{ base: '100%' }" centered>
<ds-space style="text-align: center" margin-top="large" margin-bottom="xxx-small" centered>
<div class="ds-container ds-container-small">
<div class="ds-flex">
<div style="flex: 0 0 100%; width: 100%; align-self: center">
<div style="text-align: center" class="ds-mt-large ds-mb-xxx-small ds-space-centered">
<logo logoType="logout" />
</ds-space>
<ds-space style="text-align: center" margin-top="small" margin-bottom="xxx-small" centered>
<ds-heading tag="h3" soft>Logging out...</ds-heading>
</ds-space>
</ds-flex-item>
</ds-flex>
</ds-container>
</div>
<div style="text-align: center" class="ds-mt-small ds-mb-xxx-small ds-space-centered">
<h3 class="ds-heading ds-heading-h3 ds-heading-soft">{{ $t('login.loggingOut') }}</h3>
</div>
</div>
</div>
</div>
</template>
<script>

View File

@ -1,8 +1,8 @@
<!-- Example Reference: https://codesandbox.io/s/v-mapbox-with-nuxt-lbrt6?file=/pages/index.vue -->
<template>
<div>
<ds-space margin="small">
<ds-heading tag="h1">{{ $t('map.pageTitle') }}</ds-heading>
<div class="ds-my-small">
<h1 class="ds-heading ds-heading-h1">{{ $t('map.pageTitle') }}</h1>
<small>
<div>
<span v-for="type in markers.types" :key="type.id">
@ -16,9 +16,9 @@
</span>
</div>
</small>
</ds-space>
</div>
<ds-space margin="small" />
<div class="ds-my-small"></div>
<client-only v-if="!isEmpty($env.MAPBOX_TOKEN)">
<map-styles-buttons
v-if="isMobile"

View File

@ -1,18 +1,18 @@
<template>
<div>
<ds-heading tag="h1">
<h1 class="ds-heading ds-heading-h1">
{{ $t('moderation.name') }}
</ds-heading>
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', md: '200px' }">
</h1>
<div class="ds-flex ds-flex-gap-small moderation-layout">
<div class="moderation-layout__sidebar">
<ds-menu :routes="routes" />
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', md: 1 }">
</div>
<div class="moderation-layout__main">
<transition name="slide-up" appear>
<nuxt-child />
</transition>
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
</template>
@ -31,3 +31,20 @@ export default {
},
}
</script>
<style lang="scss">
.moderation-layout__sidebar,
.moderation-layout__main {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-medium} {
.moderation-layout__sidebar {
flex: 0 0 200px;
width: 200px;
}
.moderation-layout__main {
flex: 1 0 0;
}
}
</style>

View File

@ -1,17 +1,17 @@
<template>
<os-card>
<ds-flex class="notifications-page-flex">
<ds-flex-item :width="{ lg: '85%' }">
<ds-heading tag="h3">{{ $t('notifications.title') }}</ds-heading>
</ds-flex-item>
<ds-flex-item width="110px">
<div class="ds-flex notifications-page-flex">
<div class="notifications-layout__title">
<h3 class="ds-heading ds-heading-h3">{{ $t('notifications.title') }}</h3>
</div>
<div style="flex: 0 0 110px; width: 110px">
<client-only>
<dropdown-filter @filter="filter" :filterOptions="filterOptions" :selected="selected" />
</client-only>
</ds-flex-item>
</ds-flex>
<ds-space />
<ds-flex-item class="notifications-header-button" :width="{ base: 'auto' }" centered>
</div>
</div>
<div class="ds-mb-large"></div>
<div class="notifications-header-button" style="flex: 0 0 auto; align-self: center">
<os-button
variant="primary"
appearance="outline"
@ -21,23 +21,23 @@
>
{{ $t('notifications.markAllAsRead') }}
</os-button>
</ds-flex-item>
<ds-space />
</div>
<div class="ds-mb-large"></div>
<notifications-table
@markNotificationAsRead="markNotificationAsRead"
:notifications="notifications"
/>
<ds-flex class="notifications-footer">
<ds-flex-item :width="{ base: 'auto' }" centered>
<div class="ds-flex notifications-footer">
<div style="flex: 0 0 auto; align-self: center">
<pagination-buttons
:hasNext="hasNext"
:hasPrevious="hasPrevious"
@back="back"
@next="next"
/>
</ds-flex-item>
</ds-flex>
</div>
</div>
</os-card>
</template>
@ -157,6 +157,12 @@ export default {
}
</script>
<style lang="scss">
@media #{$media-query-large} {
.notifications-layout__title {
flex: 0 0 85%;
width: 85%;
}
}
.notifications-page-flex {
padding: 8px;
justify-content: space-between;

View File

@ -1,5 +1,5 @@
<template>
<ds-container width="small" class="password-reset">
<div class="ds-container ds-container-small password-reset">
<div class="back-link">
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</div>
@ -17,7 +17,7 @@
<locale-switch offset="5" />
</aside>
</os-card>
</ds-container>
</div>
</template>
<script>

View File

@ -4,9 +4,9 @@
:nonce="nonce"
@passwordResetResponse="handlePasswordResetResponse"
>
<ds-space centered>
<div class="ds-mb-large ds-space-centered">
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</ds-space>
</div>
</change-password>
</template>

View File

@ -1,8 +1,8 @@
<template>
<enter-nonce :email="email" @nonceEntered="nonceEntered">
<ds-space margin-bottom="xxx-small" margin-top="large" centered>
<div class="ds-mb-xxx-small ds-mt-large ds-space-centered">
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</ds-space>
</div>
</enter-nonce>
</template>

View File

@ -1,20 +1,23 @@
<template>
<transition name="fade" appear>
<div>
<ds-space margin="small">
<ds-heading tag="h1">{{ heading }}</ds-heading>
<ds-heading v-if="post && post.group && post.group.id && post.group.slug" tag="h2">
<div class="ds-my-small">
<h1 class="ds-heading ds-heading-h1">{{ heading }}</h1>
<h2
v-if="post && post.group && post.group.id && post.group.slug"
class="ds-heading ds-heading-h2"
>
{{ $t('post.viewPost.forGroup.title') }}
<nuxt-link
:to="{ name: 'groups-id-slug', params: { slug: post.group.slug, id: post.group.id } }"
>
{{ post.group.name }}
</nuxt-link>
</ds-heading>
</ds-space>
<ds-space margin="large" />
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }">
</h2>
</div>
<div class="ds-my-large"></div>
<div class="ds-flex ds-flex-gap-small post-detail-layout">
<div class="post-detail-layout__main">
<os-card
v-if="post && ready"
:lang="post.language"
@ -51,9 +54,9 @@
<section class="menu">
<user-teaser :user="post.author" :group="post.group" wide :date-time="post.createdAt">
<template #dateTime>
<ds-text v-if="post.createdAt !== post.updatedAt">
<p class="ds-text" v-if="post.createdAt !== post.updatedAt">
({{ $t('post.edited') }})
</ds-text>
</p>
</template>
</user-teaser>
<client-only>
@ -73,12 +76,12 @@
/>
</client-only>
</section>
<ds-space margin-bottom="small" />
<div class="ds-mb-small"></div>
<h2 class="title hyphenate-text">{{ post.title }}</h2>
<!-- event data -->
<ds-space
<div
v-if="post && post.postType[0] === 'Event'"
margin-bottom="small"
class="ds-mb-small"
style="padding: 10px"
>
<location-teaser
@ -92,14 +95,14 @@
:startDate="post.eventStart"
:endDate="post.eventEnd"
/>
</ds-space>
<ds-space margin-bottom="small" />
</div>
<div class="ds-mb-small"></div>
<!-- content -->
<content-viewer class="content hyphenate-text" :content="post.content" />
<!-- categories -->
<div v-if="categoriesActive && post.categories.length > 0" class="categories">
<ds-space margin="xx-large" />
<ds-space margin="xx-small" />
<div class="ds-my-xx-large"></div>
<div class="ds-my-xx-small"></div>
<hc-category
v-for="category in sortCategories(post.categories)"
:key="category.id"
@ -111,10 +114,10 @@
}"
/>
</div>
<ds-space margin-bottom="small" />
<div class="ds-mb-small"></div>
<!-- Tags -->
<div v-if="post.tags && post.tags.length" class="tags">
<ds-space margin="xx-small" />
<div class="ds-my-xx-small"></div>
<hc-hashtag v-for="tag in sortedTags" :key="tag.id" :id="tag.id" />
</div>
<div class="actions">
@ -135,14 +138,14 @@
/>
</div>
<!-- comments -->
<ds-section>
<section class="ds-section">
<!-- comment list -->
<comment-list
:post="post"
@toggleNewCommentForm="toggleNewCommentForm"
@reply="reply"
/>
<ds-space margin-bottom="large" />
<div class="ds-mb-large"></div>
<!-- commenting form -->
<comment-form
v-if="
@ -155,7 +158,7 @@
@createComment="createComment"
/>
<!-- commenting disabled -->
<ds-placeholder v-else>
<div class="ds-placeholder" v-else>
<hc-empty
margin="xxx-small"
icon="messages"
@ -168,14 +171,14 @@
@update="updateJoinLeave"
/>
</hc-empty>
</ds-placeholder>
</ds-section>
</div>
</section>
</os-card>
</ds-flex-item>
<ds-flex-item :width="{ base: '200px' }">
</div>
<div class="post-detail-layout__sidebar" style="flex: 0 0 200px; width: 200px">
<ds-menu :routes="routes" class="post-side-navigation" />
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
</transition>
</template>
@ -421,6 +424,25 @@ export default {
</script>
<style lang="scss">
.post-detail-layout__main {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-small} {
.post-detail-layout__main {
flex: 2 0 0;
}
}
@media #{$media-query-medium} {
.post-detail-layout__main {
flex: 2 0 0;
}
}
@media #{$media-query-large} {
.post-detail-layout__main {
flex: 1 0 0;
}
}
.post-side-navigation {
position: sticky;
top: 65px;

View File

@ -1,19 +1,19 @@
<template>
<div>
<ds-space margin="small">
<ds-heading tag="h1">
<div class="ds-my-small">
<h1 class="ds-heading ds-heading-h1">
{{ heading }}
</ds-heading>
<ds-heading v-if="group && group.id && group.slug" tag="h2">
</h1>
<h2 v-if="group && group.id && group.slug" class="ds-heading ds-heading-h2">
{{ $t('post.viewPost.forGroup.title') }}
<nuxt-link :to="{ name: 'groups-id-slug', params: { slug: group.slug, id: group.id } }">
{{ group.name }}
</nuxt-link>
</ds-heading>
</ds-space>
<ds-space margin="large" />
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', md: '200px' }">
</h2>
</div>
<div class="ds-my-large"></div>
<div class="ds-flex ds-flex-gap-small post-create-layout">
<div class="post-create-layout__sidebar">
<ds-menu :routes="routes">
<ds-menu-item
@click.prevent="switchPostType($event, item)"
@ -24,13 +24,13 @@
{{ item.route.name }}
</ds-menu-item>
</ds-menu>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', md: 1 }">
</div>
<div class="post-create-layout__main">
<transition name="slide-up" appear>
<contribution-form :group="group" :createEvent="createEvent" />
</transition>
</ds-flex-item>
</ds-flex>
</div>
</div>
</div>
</template>
@ -132,4 +132,19 @@ export default {
.ds-heading {
margin-top: 0;
}
.post-create-layout__sidebar,
.post-create-layout__main {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-medium} {
.post-create-layout__sidebar {
flex: 0 0 200px;
width: 200px;
}
.post-create-layout__main {
flex: 1 0 0;
}
}
</style>

View File

@ -1,14 +1,14 @@
<template>
<div>
<ds-space margin="small">
<ds-heading tag="h1">
<div class="ds-my-small">
<h1 class="ds-heading ds-heading-h1">
{{ heading }}
</ds-heading>
<ds-heading
</h1>
<h2
v-if="
contribution && contribution.group && contribution.group.id && contribution.group.slug
"
tag="h2"
class="ds-heading ds-heading-h2"
>
{{ $t('post.editPost.forGroup.title') }}
<nuxt-link
@ -19,19 +19,19 @@
>
{{ contribution.group.name }}
</nuxt-link>
</ds-heading>
</ds-space>
<ds-space margin="large" />
<ds-flex :width="{ base: '100%' }" gutter="base">
<ds-flex-item :width="{ base: '100%', md: 3 }">
</h2>
</div>
<div class="ds-my-large"></div>
<div class="ds-flex ds-flex-gap-base post-edit-layout">
<div class="post-edit-layout__main">
<contribution-form
:contribution="contribution"
:group="contribution && contribution.group ? contribution.group : null"
:createEvent="contribution && contribution.postType[0] === 'Event'"
/>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', md: 1 }">&nbsp;</ds-flex-item>
</ds-flex>
</div>
<div class="post-edit-layout__aside"></div>
</div>
</div>
</template>
@ -89,4 +89,18 @@ export default {
.ds-heading {
margin-top: 0;
}
.post-edit-layout__main,
.post-edit-layout__aside {
flex: 0 0 100%;
width: 100%;
}
@media #{$media-query-medium} {
.post-edit-layout__main {
flex: 3 0 0;
}
.post-edit-layout__aside {
flex: 1 0 0;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More