(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
98
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">