(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Lichen bookmarks support

+336 -219
+2 -1
backend/internal/api/hydration.go
··· 822 822 annotationURIs = append(annotationURIs, uri) 823 823 case strings.Contains(uri, "at.margin.highlight"): 824 824 highlightURIs = append(highlightURIs, uri) 825 - case strings.Contains(uri, "at.margin.bookmark"): 825 + case strings.Contains(uri, "at.margin.bookmark"), 826 + strings.Contains(uri, "wiki.lichen.bookmark"): 826 827 bookmarkURIs = append(bookmarkURIs, uri) 827 828 case strings.Contains(uri, "network.cosmik.card"): 828 829 annotationURIs = append(annotationURIs, uri)
+35
backend/internal/firehose/ingester.go
··· 95 95 i.RegisterHandler(CollectionDocument, i.handleDocument) 96 96 i.RegisterHandler(xrpc.CollectionNote, i.handleNote) 97 97 i.RegisterHandler(xrpc.CollectionCommunityBookmark, i.handleCommunityBookmark) 98 + i.RegisterHandler(xrpc.CollectionLichenBookmark, i.handleLichenBookmark) 98 99 99 100 return i 100 101 } ··· 331 332 i.db.DeleteNote(uri) 332 333 case xrpc.CollectionCommunityBookmark: 333 334 i.db.DeleteNote(uri) 335 + case xrpc.CollectionLichenBookmark: 336 + i.db.DeleteBookmark(uri) 334 337 } 335 338 } 336 339 ··· 1302 1305 } 1303 1306 }) 1304 1307 } 1308 + 1309 + func (i *Ingester) handleLichenBookmark(event *FirehoseEvent) { 1310 + var record xrpc.LichenBookmark 1311 + if err := json.Unmarshal(event.Record, &record); err != nil { 1312 + return 1313 + } 1314 + 1315 + source := xrpc.LichenWikiURLFromRef(record.WikiRef) 1316 + if source == "" { 1317 + return 1318 + } 1319 + 1320 + uri := fmt.Sprintf("at://%s/%s/%s", event.Repo, event.Collection, event.Rkey) 1321 + createdAt, err := time.Parse(time.RFC3339, record.CreatedAt) 1322 + if err != nil { 1323 + createdAt = time.Now() 1324 + } 1325 + 1326 + bookmark := &db.Bookmark{ 1327 + URI: uri, 1328 + AuthorDID: event.Repo, 1329 + Source: source, 1330 + SourceHash: db.HashURL(source), 1331 + CreatedAt: createdAt, 1332 + IndexedAt: time.Now(), 1333 + } 1334 + if err := i.db.CreateBookmark(bookmark); err != nil { 1335 + logger.Error("Failed to index Lichen bookmark: %v", err) 1336 + } else { 1337 + logger.Info("Indexed Lichen bookmark from %s: %s", event.Repo, source) 1338 + } 1339 + }
+27
backend/internal/sync/service.go
··· 41 41 xrpc.CollectionSembleCard, 42 42 xrpc.CollectionSembleCollection, 43 43 xrpc.CollectionSembleCollectionLink, 44 + xrpc.CollectionLichenBookmark, 44 45 xrpc.CollectionDocument, 45 46 } 46 47 ··· 208 209 } else { 209 210 err = e 210 211 } 212 + case xrpc.CollectionLichenBookmark: 213 + localURIs, err = s.db.GetBookmarkURIs(did) 214 + localURIs = filterURIsByCollection(localURIs, xrpc.CollectionLichenBookmark) 211 215 } 212 216 213 217 if err == nil { ··· 239 243 _ = s.db.DeleteAPIKeyByURI(uri) 240 244 case xrpc.CollectionPreferences: 241 245 _ = s.db.DeletePreferences(uri) 246 + case xrpc.CollectionLichenBookmark: 247 + _ = s.db.DeleteBookmark(uri) 242 248 } 243 249 deletedCount++ 244 250 } ··· 627 633 Position: 0, 628 634 CreatedAt: createdAt, 629 635 IndexedAt: time.Now(), 636 + }) 637 + 638 + case xrpc.CollectionLichenBookmark: 639 + var record xrpc.LichenBookmark 640 + if err := json.Unmarshal(value, &record); err != nil { 641 + return err 642 + } 643 + source := xrpc.LichenWikiURLFromRef(record.WikiRef) 644 + if source == "" { 645 + return nil 646 + } 647 + createdAt, _ := time.Parse(time.RFC3339, record.CreatedAt) 648 + 649 + return s.db.CreateBookmark(&db.Bookmark{ 650 + URI: uri, 651 + AuthorDID: did, 652 + Source: source, 653 + SourceHash: db.HashURL(source), 654 + CreatedAt: createdAt, 655 + IndexedAt: time.Now(), 656 + CID: cidPtr, 630 657 }) 631 658 632 659 case xrpc.CollectionAPIKey:
+26
backend/internal/xrpc/lichen.go
··· 1 + package xrpc 2 + 3 + import "strings" 4 + 5 + const ( 6 + CollectionLichenBookmark = "wiki.lichen.bookmark" 7 + CollectionLichenWiki = "wiki.lichen.wiki" 8 + ) 9 + 10 + type LichenBookmark struct { 11 + WikiRef string `json:"wikiRef"` 12 + CreatedAt string `json:"createdAt"` 13 + } 14 + 15 + func LichenWikiURLFromRef(wikiRef string) string { 16 + rest := strings.TrimPrefix(wikiRef, "at://") 17 + parts := strings.Split(rest, "/") 18 + if len(parts) < 3 || parts[1] != CollectionLichenWiki { 19 + return "" 20 + } 21 + rkey := parts[len(parts)-1] 22 + if rkey == "" { 23 + return "" 24 + } 25 + return "https://lichen.wiki/wiki/" + rkey 26 + }
+8
web/public/lichen-logo.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 134.92644 128.42101"> 2 + <g transform="matrix(1.1,0,0,1.1,301.47096,350.25297)"> 3 + <path 4 + fill="#0f766e" 5 + d="m -228.35257,-262.99296 c -19.02978,5.17331 5.71835,53.17295 -8.81529,55.61911 -13.95583,2.34891 0.99206,-24.53241 -15.5475,-43.46739 -15.47347,-6.08381 -20.6167,-0.72715 -21.15703,-6.95845 -1.3108,-15.1168 3.95665,-3.71429 19.79401,-8.66631 10.82433,-3.38455 8.09155,-17.08945 3.51308,-19.68708 -14.62332,-8.29661 -0.4486,-21.17177 10.05655,-4.9252 4.71302,9.40824 16.36423,20.32455 18.35849,1.52382 1.60655,-15.14555 2.81668,-16.44355 8.53544,-24.19918 5.90154,-8.00349 25.08044,-4.44133 20.58215,1.31991 -5.02364,6.43406 -7.98538,3.21247 -14.05766,18.33414 -12.75512,31.76381 6.97901,29.69424 13.71761,37.34873 4.34654,4.93731 7.24489,-0.30345 10.876,-6.12677 8,-12 7.33137,-12.59361 13.33137,-20.59361 6,-6 3.48697,-14.27094 11.48697,-8.27094 2.14738,1.61054 8.33559,11.3398 5.57936,13.31991 -7.65995,1.7579 -6.25355,1.42931 -12.25355,11.42931 -6,10 -12,22 -16,30 4,6 3.7579,16.36888 5.7579,28.36888 -6.36045,10.47209 -14.25746,-0.3673 -24.05766,6.32268 -6.32302,4.31633 -20.20337,-14.76624 -11.82391,-14.37787 28.84239,1.33675 17.02084,-2.92172 15.35708,-20.34251 -10.88292,-10.19367 -16.95709,-23.80355 -33.23341,-25.97118 z" 6 + /> 7 + </g> 8 + </svg>
+219 -218
web/public/locales/cs/translation.json
··· 1 1 { 2 - "nav": { 3 - "discover": "Objevuj", 4 - "activity": "Notifikace", 5 - "bookmarks": "Záložky", 6 - "annotations": "Vpisky", 7 - "highlights": "Úryvky", 8 - "collections": "Složky", 9 - "signIn": "Přihlásit se", 10 - "logOut": "Odhlásit se", 11 - "feed": "Feed", 12 - "settings": "Nastavení", 13 - "new": "Anotovat", 14 - "themeLight": "Světlo", 15 - "themeDark": "Tma", 16 - "themeSystem": "Režim podle OS" 2 + "nav": { 3 + "discover": "Objevuj", 4 + "activity": "Notifikace", 5 + "bookmarks": "Záložky", 6 + "annotations": "Vpisky", 7 + "highlights": "Úryvky", 8 + "collections": "Složky", 9 + "signIn": "Přihlásit se", 10 + "logOut": "Odhlásit se", 11 + "feed": "Feed", 12 + "settings": "Nastavení", 13 + "new": "Anotovat", 14 + "themeLight": "Světlo", 15 + "themeDark": "Tma", 16 + "themeSystem": "Režim podle OS" 17 + }, 18 + "appTitle": "Margin", 19 + "feed": { 20 + "mine": "Pouze já", 21 + "everyone": "Všichni", 22 + "filters": { 23 + "bookmarks": "Záložky", 24 + "highlights": "Úryvky" 17 25 }, 18 - "appTitle": "Margin", 19 - "feed": { 20 - "mine": "Pouze já", 21 - "everyone": "Všichni", 22 - "filters": { 23 - "bookmarks": "Záložky", 24 - "highlights": "Úryvky" 25 - }, 26 - "itemsWithTag": "Položky se štítkem:", 27 - "tabs": { 28 - "recent": "Nedávné", 29 - "popular": "Populární", 30 - "shelved": "Málo diskutované" 31 - }, 32 - "welcome": "Vítejte na Marginu", 33 - "getStarted": "Pustit se do toho", 34 - "clearFilter": "Odepnout filtr", 35 - "loading": "Načítání…", 36 - "nothingHereYet": "Prozatím tady nic není" 26 + "itemsWithTag": "Položky se štítkem:", 27 + "tabs": { 28 + "recent": "Nedávné", 29 + "popular": "Populární", 30 + "shelved": "Málo diskutované" 37 31 }, 38 - "collections": { 39 - "title": "Složky", 40 - "namePlaceholderEdit": "Název složky", 41 - "nameLabel": "Název", 42 - "iconLabel": "Ikona", 43 - "iconsTab": "Ikony", 44 - "emojisTab": "Emotikony", 45 - "selectedIcon": "Vybráno:", 46 - "descriptionLabel": "Popisek (volitelně)", 47 - "descriptionPlaceholder": "K čemu by měla tato složka sloužit?", 48 - "descriptionPlaceholderEdit": "O čem by měla být tato složka?", 49 - "cancel": "Zrušit", 50 - "creating": "Vytvářím…", 51 - "save": "Uložit změny", 52 - "saving": "Ukládám…", 53 - "subtitle": "Uspořádejte si vpisky a úryvky", 54 - "namePlaceholder": "Moje složka", 55 - "createButton": "Vytvořit složku", 56 - "editTitle": "Upravit složku", 57 - "newTitle": "Nová složka", 58 - "create": "Vytvořit složku", 59 - "noneMessage": "Vytvořte si novou složku k organizaci Vašich vpisků a úryvků." 32 + "welcome": "Vítejte na Marginu", 33 + "getStarted": "Pustit se do toho", 34 + "clearFilter": "Odepnout filtr", 35 + "loading": "Načítání…", 36 + "nothingHereYet": "Prozatím tady nic není" 37 + }, 38 + "collections": { 39 + "title": "Složky", 40 + "namePlaceholderEdit": "Název složky", 41 + "nameLabel": "Název", 42 + "iconLabel": "Ikona", 43 + "iconsTab": "Ikony", 44 + "emojisTab": "Emotikony", 45 + "selectedIcon": "Vybráno:", 46 + "descriptionLabel": "Popisek (volitelně)", 47 + "descriptionPlaceholder": "K čemu by měla tato složka sloužit?", 48 + "descriptionPlaceholderEdit": "O čem by měla být tato složka?", 49 + "cancel": "Zrušit", 50 + "creating": "Vytvářím…", 51 + "save": "Uložit změny", 52 + "saving": "Ukládám…", 53 + "subtitle": "Uspořádejte si vpisky a úryvky", 54 + "namePlaceholder": "Moje složka", 55 + "createButton": "Vytvořit složku", 56 + "editTitle": "Upravit složku", 57 + "newTitle": "Nová složka", 58 + "create": "Vytvořit složku", 59 + "noneMessage": "Vytvořte si novou složku k organizaci Vašich vpisků a úryvků." 60 + }, 61 + "about": { 62 + "footer": { 63 + "contact": "Kontakt", 64 + "terms": "Smluvní podmínky", 65 + "privacy": "Ochrana soukromí" 60 66 }, 61 - "about": { 62 - "footer": { 63 - "contact": "Kontakt", 64 - "terms": "Smluvní podmínky", 65 - "privacy": "Ochrana soukromí" 66 - }, 67 - "cta": { 68 - "viewGitHub": "GitHub", 69 - "viewTangled": "Tangled", 70 - "signIn": "Přihlásit se", 71 - "title": "Začněte psát pod čarou" 72 - }, 73 - "protocol": { 74 - "descriptionPre": "Margin je vystavěn na" 75 - }, 76 - "extension": { 77 - "features": { 78 - "keyboard": { 79 - "title": "Klávesové zkratky" 80 - } 81 - } 82 - } 67 + "cta": { 68 + "viewGitHub": "GitHub", 69 + "viewTangled": "Tangled", 70 + "signIn": "Přihlásit se", 71 + "title": "Začněte psát pod čarou" 83 72 }, 84 - "profile": { 85 - "unblock_action": "Zablokovat", 86 - "unmute_action": "Ztišit", 87 - "emptyCollectionsOwn": "Prozatím jste si nevytvořili žádné složky.", 88 - "emptyCollectionsOther": "Žádné složky", 89 - "show": "Zobrazit", 90 - "hide": "Skrýt" 73 + "protocol": { 74 + "descriptionPre": "Margin je vystavěn na" 91 75 }, 92 - "pageTitles": { 93 - "discover": "Objevuj — Margin", 94 - "home": "Úvod — Margin", 95 - "bookmarks": "Záložky — Margin", 96 - "settings": "Nastavení — Margin", 97 - "collections": "Složky — Margin", 98 - "admin": "Administrace — Margin", 99 - "search": "Vyhledávání — Margin", 100 - "notifications": "Notifikace — Margin", 101 - "new": "Nový vpisek — Margin", 102 - "highlights": "Úryvky — Margin", 103 - "annotations": "Vpisky — Margin" 104 - }, 105 - "sidebar": { 106 - "downloadForFirefox": "Stáhnout pro Firefox", 107 - "downloadForEdge": "Stáhnout pro Edge", 108 - "downloadForChrome": "Stáhnout pro Chrome", 109 - "trending": "Populární", 110 - "searchPlaceholder": "Vyhledávejte napříč uživateli, tagy, URL…", 111 - "getExtension": "Stáhnout rozšíření", 112 - "nothingTrending": "Aktuálně není nic moc v kurzu." 113 - }, 114 - "mobileNav": { 115 - "iosShortcut": "Zkratka iOS" 116 - }, 117 - "discover": { 118 - "tabs": { 119 - "new": "Nové", 120 - "popular": "Populární", 121 - "forYou": "Výběr" 122 - }, 123 - "comingSoon": "Již brzy", 124 - "forYouNotAvailable": "Personalizovaná doporučení nejsou na tomto serveru prozatím k dispozici.", 125 - "loadMore": "Načíst další", 126 - "noDocumentsYet": "Prozatím tady nejsou žádné dokumenty. Zkuste to znova později." 127 - }, 128 - "search": { 129 - "noResults": "Nic nenalezeno", 130 - "emptyTitle": "Vyhledávejte ve Vaší knihovně", 131 - "filters": { 132 - "all": "Všechno" 133 - }, 134 - "loadMore": "Načíst další" 135 - }, 136 - "notifications": { 137 - "inReplyTo": "v odpovědi na", 138 - "aReply": "odpověď", 139 - "anAnnotation": "vpisek", 140 - "likedAnnotation": "se líbí Váš vpisek", 141 - "likedHighlight": "se líbí Váš úryvek", 142 - "likedBookmark": "se líbí Vaše záložka", 143 - "likedReply": "se líbí Vaše odpověď", 144 - "likedPost": "se líbí Váš příspěvek", 145 - "repliedToReply": "reagoval*a na Vaši odpověď", 146 - "repliedToAnnotation": "odpověděl*a na Váš vpisek", 147 - "mentionedInAnnotation": "Vás zmínil*a ve vpisku", 148 - "followedYou": "Vás začal*a sledovat", 149 - "title": "Události", 150 - "noActivity": "Prozatím tady nic není", 151 - "highlightedPage": "si vytáhnul*a úryvek z Vaší stránky", 152 - "noActivityMessage": "Reakce na Váš obsah se objeví tady." 153 - }, 154 - "login": { 155 - "termsLink": "Smluvní podmínky", 156 - "termsAnd": "a", 157 - "privacyLink": "Zásady ochrany osobních údajů" 158 - }, 159 - "signUp": { 160 - "atProtocol": "Protokol AT", 161 - "pdsAddressLabel": "Adresa PDS", 162 - "pdsAddressPlaceholder": "pds.vasedomena.cz", 163 - "connecting": "Připojuji…", 164 - "back": "Zpátky", 165 - "continue": "Pokračovat", 166 - "invite": "Pozvat", 167 - "providerError": "K tomuto poskytovateli se teď nelze připojit. Zkuste to znova.", 168 - "customPdsError": "K tomuto PDS se teď nelze připojit. Zkontrolujte, zda zadáváte správnou adresu.", 169 - "providers": { 170 - "margin": { 171 - "name": "Margin" 172 - }, 173 - "customPds": { 174 - "description": "PDS už máte? Pokud ano, zadejte jeho adresu.", 175 - "name": "Použít vlastní PDS" 176 - }, 177 - "bluesky": { 178 - "name": "Bluesky", 179 - "description": "Největší a nejrozšířenější komunita" 180 - }, 181 - "blacksky": { 182 - "name": "Blacksky" 183 - }, 184 - "northsky": { 185 - "description": "Kanadské družstvo vlastněné a provozované zaměstnanci", 186 - "name": "Northsky" 187 - }, 188 - "eurosky": { 189 - "description": "Eurosky je Vaším kouskem Evropy v Atmosféře" 190 - }, 191 - "selfhostedSocial": { 192 - "name": "selfhosted.social", 193 - "description": "Prostor pro všechny umělce, kutily a objevitele" 194 - }, 195 - "tophhie": { 196 - "name": "Tophhie", 197 - "description": "Komunita plná přátelské atmosféry" 198 - } 76 + "extension": { 77 + "features": { 78 + "keyboard": { 79 + "title": "Klávesové zkratky" 199 80 } 81 + } 82 + } 83 + }, 84 + "profile": { 85 + "unblock_action": "Zablokovat", 86 + "unmute_action": "Ztišit", 87 + "emptyCollectionsOwn": "Prozatím jste si nevytvořili žádné složky.", 88 + "emptyCollectionsOther": "Žádné složky", 89 + "show": "Zobrazit", 90 + "hide": "Skrýt" 91 + }, 92 + "pageTitles": { 93 + "discover": "Objevuj — Margin", 94 + "home": "Úvod — Margin", 95 + "bookmarks": "Záložky — Margin", 96 + "settings": "Nastavení — Margin", 97 + "collections": "Složky — Margin", 98 + "admin": "Administrace — Margin", 99 + "search": "Vyhledávání — Margin", 100 + "notifications": "Notifikace — Margin", 101 + "new": "Nový vpisek — Margin", 102 + "highlights": "Úryvky — Margin", 103 + "annotations": "Vpisky — Margin" 104 + }, 105 + "sidebar": { 106 + "downloadForFirefox": "Stáhnout pro Firefox", 107 + "downloadForEdge": "Stáhnout pro Edge", 108 + "downloadForChrome": "Stáhnout pro Chrome", 109 + "trending": "Populární", 110 + "searchPlaceholder": "Vyhledávejte napříč uživateli, tagy, URL…", 111 + "getExtension": "Stáhnout rozšíření", 112 + "nothingTrending": "Aktuálně není nic moc v kurzu." 113 + }, 114 + "mobileNav": { 115 + "iosShortcut": "Zkratka iOS" 116 + }, 117 + "discover": { 118 + "tabs": { 119 + "new": "Nové", 120 + "popular": "Populární", 121 + "forYou": "Výběr" 200 122 }, 201 - "composer": { 202 - "newHighlight": "Nový úryvek", 203 - "newAnnotation": "Nový vpisek", 204 - "newNote": "Nová poznámka", 205 - "saveHighlight": "Uložit úryvek", 206 - "postAnnotation": "Vložit vpisek", 207 - "postNote": "Vložit poznámku", 208 - "removeQuote": "Odebrat citaci", 209 - "labels": { 210 - "sexual": "Sexualita", 211 - "nudity": "Nahota", 212 - "violence": "Násilí", 213 - "gore": "Gore", 214 - "spam": "Spam", 215 - "misleading": "Manipulace" 216 - }, 217 - "contentWarning": "Upozornění na obsah", 218 - "cancel": "Zrušit" 123 + "comingSoon": "Již brzy", 124 + "forYouNotAvailable": "Personalizovaná doporučení nejsou na tomto serveru prozatím k dispozici.", 125 + "loadMore": "Načíst další", 126 + "noDocumentsYet": "Prozatím tady nejsou žádné dokumenty. Zkuste to znova později." 127 + }, 128 + "search": { 129 + "noResults": "Nic nenalezeno", 130 + "emptyTitle": "Vyhledávejte ve Vaší knihovně", 131 + "filters": { 132 + "all": "Všechno" 219 133 }, 220 - "card": { 221 - "communityBookmark": "Komunitní záložka", 222 - "untitledBookmark": "Nepojmenovaná záložka", 223 - "editTitle": "Upravit", 224 - "deleteTitle": "Smazat", 225 - "report": "Nahlásit", 226 - "muteUser": "Ztišit @{{handle}}", 227 - "blockUser": "Zablokovat @{{handle}}" 134 + "loadMore": "Načíst další" 135 + }, 136 + "notifications": { 137 + "inReplyTo": "v odpovědi na", 138 + "aReply": "odpověď", 139 + "anAnnotation": "vpisek", 140 + "likedAnnotation": "se líbí Váš vpisek", 141 + "likedHighlight": "se líbí Váš úryvek", 142 + "likedBookmark": "se líbí Vaše záložka", 143 + "likedReply": "se líbí Vaše odpověď", 144 + "likedPost": "se líbí Váš příspěvek", 145 + "repliedToReply": "reagoval*a na Vaši odpověď", 146 + "repliedToAnnotation": "odpověděl*a na Váš vpisek", 147 + "mentionedInAnnotation": "Vás zmínil*a ve vpisku", 148 + "followedYou": "Vás začal*a sledovat", 149 + "title": "Události", 150 + "noActivity": "Prozatím tady nic není", 151 + "highlightedPage": "si vytáhnul*a úryvek z Vaší stránky", 152 + "noActivityMessage": "Reakce na Váš obsah se objeví tady." 153 + }, 154 + "login": { 155 + "termsLink": "Smluvní podmínky", 156 + "termsAnd": "a", 157 + "privacyLink": "Zásady ochrany osobních údajů" 158 + }, 159 + "signUp": { 160 + "atProtocol": "Protokol AT", 161 + "pdsAddressLabel": "Adresa PDS", 162 + "pdsAddressPlaceholder": "pds.vasedomena.cz", 163 + "connecting": "Připojuji…", 164 + "back": "Zpátky", 165 + "continue": "Pokračovat", 166 + "invite": "Pozvat", 167 + "providerError": "K tomuto poskytovateli se teď nelze připojit. Zkuste to znova.", 168 + "customPdsError": "K tomuto PDS se teď nelze připojit. Zkontrolujte, zda zadáváte správnou adresu.", 169 + "providers": { 170 + "margin": { 171 + "name": "Margin" 172 + }, 173 + "customPds": { 174 + "description": "PDS už máte? Pokud ano, zadejte jeho adresu.", 175 + "name": "Použít vlastní PDS" 176 + }, 177 + "bluesky": { 178 + "name": "Bluesky", 179 + "description": "Největší a nejrozšířenější komunita" 180 + }, 181 + "blacksky": { 182 + "name": "Blacksky" 183 + }, 184 + "northsky": { 185 + "description": "Kanadské družstvo vlastněné a provozované zaměstnanci", 186 + "name": "Northsky" 187 + }, 188 + "eurosky": { 189 + "description": "Eurosky je Vaším kouskem Evropy v Atmosféře" 190 + }, 191 + "selfhostedSocial": { 192 + "name": "selfhosted.social", 193 + "description": "Prostor pro všechny umělce, kutily a objevitele" 194 + }, 195 + "tophhie": { 196 + "name": "Tophhie", 197 + "description": "Komunita plná přátelské atmosféry" 198 + } 228 199 } 200 + }, 201 + "composer": { 202 + "newHighlight": "Nový úryvek", 203 + "newAnnotation": "Nový vpisek", 204 + "newNote": "Nová poznámka", 205 + "saveHighlight": "Uložit úryvek", 206 + "postAnnotation": "Vložit vpisek", 207 + "postNote": "Vložit poznámku", 208 + "removeQuote": "Odebrat citaci", 209 + "labels": { 210 + "sexual": "Sexualita", 211 + "nudity": "Nahota", 212 + "violence": "Násilí", 213 + "gore": "Gore", 214 + "spam": "Spam", 215 + "misleading": "Manipulace" 216 + }, 217 + "contentWarning": "Upozornění na obsah", 218 + "cancel": "Zrušit" 219 + }, 220 + "card": { 221 + "communityBookmark": "Komunitní záložka", 222 + "lichenBookmark": "Záložka Lichen", 223 + "untitledBookmark": "Nepojmenovaná záložka", 224 + "editTitle": "Upravit", 225 + "deleteTitle": "Smazat", 226 + "report": "Nahlásit", 227 + "muteUser": "Ztišit @{{handle}}", 228 + "blockUser": "Zablokovat @{{handle}}" 229 + } 229 230 }
+1
web/public/locales/en/translation.json
··· 285 285 "addedToLower": "added to", 286 286 "and": "and", 287 287 "communityBookmark": "Community bookmark", 288 + "lichenBookmark": "Lichen bookmark", 288 289 "openInSemble": "Open in Semble", 289 290 "deleteConfirm": "Delete this item?", 290 291 "hideContent": "Hide Content",
+1
web/public/locales/es/translation.json
··· 278 278 "addedToLower": "añadido a", 279 279 "and": "y", 280 280 "communityBookmark": "Marcador de la comunidad", 281 + "lichenBookmark": "Marcador de Lichen", 281 282 "openInSemble": "Abrir en Semble", 282 283 "deleteConfirm": "¿Eliminar este elemento?", 283 284 "hideContent": "Ocultar contenido",
+17
web/src/components/common/Card.tsx
··· 178 178 const isSemble = 179 179 item.uri?.includes("network.cosmik") || item.uri?.includes("semble"); 180 180 181 + const isLichen = item.uri?.includes("wiki.lichen.bookmark"); 182 + 181 183 const isCommunityBookmark = item.uri?.includes( 182 184 "community.lexicon.bookmarks.bookmark", 183 185 ); ··· 504 506 </span> 505 507 ); 506 508 })()} 509 + 510 + {isLichen && ( 511 + <span className="relative inline-flex items-center"> 512 + <span className="text-surface-300 dark:text-surface-600"> 513 + · 514 + </span> 515 + <span className="group/lichen relative inline-flex items-center ml-1"> 516 + <img src="/lichen-logo.svg" alt="Lichen" className="h-3.5" /> 517 + <span className="pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2.5 py-1 rounded-lg bg-surface-800 dark:bg-surface-700 text-white text-[11px] font-medium whitespace-nowrap opacity-0 group-hover/lichen:opacity-100 transition-opacity shadow-lg"> 518 + {t("card.lichenBookmark")} 519 + <span className="absolute top-full left-1/2 -translate-x-1/2 -mt-px border-4 border-transparent border-t-surface-800 dark:border-t-surface-700" /> 520 + </span> 521 + </span> 522 + </span> 523 + )} 507 524 508 525 {isCommunityBookmark && ( 509 526 <span className="relative inline-flex items-center">