diff --git a/.github/workflows/build-submit-android.yml b/.github/workflows/build-submit-android.yml
index 051e951510..8cbd90984c 100644
--- a/.github/workflows/build-submit-android.yml
+++ b/.github/workflows/build-submit-android.yml
@@ -26,9 +26,9 @@ jobs:
uses: actions/checkout@v4
- name: š§ Setup Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18.x
+ node-version-file: .nvmrc
cache: yarn
- name: šØ Setup EAS
@@ -49,10 +49,14 @@ jobs:
- name: āļø Install dependencies
run: yarn install
+ - name: š¤ Compile translations
+ run: yarn intl:build
+
- name: āļø Write environment variables
run: |
+ export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
- echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
+ echo "$json" > google-services.json
- name: šļø EAS Build
run: yarn use-build-number eas build -p android --profile production --local --output build.aab --non-interactive
diff --git a/.github/workflows/build-submit-ios.yml b/.github/workflows/build-submit-ios.yml
index 0fd691bb92..f5188b4b4b 100644
--- a/.github/workflows/build-submit-ios.yml
+++ b/.github/workflows/build-submit-ios.yml
@@ -28,9 +28,9 @@ jobs:
uses: actions/checkout@v4
- name: š§ Setup Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18.x
+ node-version-file: .nvmrc
cache: yarn
- name: šØ Setup EAS
@@ -60,6 +60,9 @@ jobs:
# change unless the yarn version changes as well.
key: ${{ runner.os }}-pods-${{ hashFiles('yarn.lock') }}
+ - name: š¤ Compile translations
+ run: yarn intl:build
+
- name: āļø Write environment variables
run: |
echo "${{ secrets.ENV_TOKEN }}" > .env
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 508da536b5..9aa55ca07a 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -32,12 +32,12 @@ jobs:
name: Run tests
runs-on: ubuntu-latest
steps:
- - name: Install node 18
- uses: actions/setup-node@v4
- with:
- node-version: 18
- name: Check out Git repository
uses: actions/checkout@v3
+ - name: Install node
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: .nvmrc
- name: Yarn install
uses: Wandalen/wretry.action@master
with:
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000000..3c032078a4
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+18
diff --git a/Dockerfile b/Dockerfile
index 47afa61a36..3ad05b6ec6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -23,7 +23,7 @@ COPY . .
RUN mkdir --parents $NVM_DIR && \
wget \
--output-document=/tmp/nvm-install.sh \
- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh && \
+ https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh && \
bash /tmp/nvm-install.sh
RUN \. "$NVM_DIR/nvm.sh" && \
@@ -31,7 +31,7 @@ RUN \. "$NVM_DIR/nvm.sh" && \
nvm use $NODE_VERSION && \
npm install --global yarn && \
yarn && \
- yarn intl:compile && \
+ yarn intl:build && \
yarn build-web
# DEBUG
diff --git a/README.md b/README.md
index 0cbfe77377..49c4b016ff 100644
--- a/README.md
+++ b/README.md
@@ -65,8 +65,6 @@ If you discover any security issues, please send an email to security@bsky.app.
Bluesky is an open social network built on the AT Protocol, a flexible technology that will never lock developers out of the ecosystems that they help build. With atproto, third-party can be as seamless as first-party through custom feeds, federated services, clients, and more.
-If you're a developer interested in building on atproto, we'd love to email you a Bluesky invite code. Simply share your GitHub (or similar) profile with us via [this form](https://forms.gle/BF21oxVNZiDjDhXF9).
-
## License (MIT)
See [./LICENSE](./LICENSE) for the full license.
diff --git a/app.config.js b/app.config.js
index e710420b09..2552d34897 100644
--- a/app.config.js
+++ b/app.config.js
@@ -11,6 +11,17 @@ const DARK_SPLASH_CONFIG = {
resizeMode: 'cover',
}
+const SPLASH_CONFIG_ANDROID = {
+ backgroundColor: '#0c7cff',
+ image: './assets/splash.png',
+ resizeMode: 'cover',
+}
+const DARK_SPLASH_CONFIG_ANDROID = {
+ backgroundColor: '#0f141b',
+ image: './assets/splash-dark.png',
+ resizeMode: 'cover',
+}
+
module.exports = function (config) {
/**
* App version number. Should be incremented as part of a release cycle.
@@ -65,10 +76,13 @@ module.exports = function (config) {
...SPLASH_CONFIG,
dark: DARK_SPLASH_CONFIG,
},
+ entitlements: {
+ 'com.apple.security.application-groups': 'group.app.bsky',
+ },
},
androidStatusBar: {
- barStyle: 'dark-content',
- backgroundColor: '#ffffff',
+ barStyle: 'light-content',
+ backgroundColor: '#00000000',
},
android: {
icon: './assets/icon.png',
@@ -89,13 +103,17 @@ module.exports = function (config) {
scheme: 'https',
host: 'bsky.app',
},
+ {
+ scheme: 'http',
+ host: 'localhost:19006',
+ },
],
category: ['BROWSABLE', 'DEFAULT'],
},
],
splash: {
- ...SPLASH_CONFIG,
- dark: DARK_SPLASH_CONFIG,
+ ...SPLASH_CONFIG_ANDROID,
+ dark: DARK_SPLASH_CONFIG_ANDROID,
},
},
web: {
@@ -114,12 +132,14 @@ module.exports = function (config) {
{
ios: {
deploymentTarget: '13.4',
+ newArchEnabled: false,
},
android: {
compileSdkVersion: 34,
targetSdkVersion: 34,
buildToolsVersion: '34.0.0',
kotlinVersion: '1.8.0',
+ newArchEnabled: false,
},
},
],
@@ -133,13 +153,33 @@ module.exports = function (config) {
'expo-notifications',
{
icon: './assets/icon-android-notification.png',
- color: '#ffffff',
+ color: '#1185fe',
},
],
'./plugins/withAndroidManifestPlugin.js',
+ './plugins/withAndroidManifestFCMIconPlugin.js',
+ './plugins/withAndroidStylesWindowBackgroundPlugin.js',
+ './plugins/shareExtension/withShareExtensions.js',
].filter(Boolean),
extra: {
eas: {
+ build: {
+ experimental: {
+ ios: {
+ appExtensions: [
+ {
+ targetName: 'Share-with-Bluesky',
+ bundleIdentifier: 'xyz.blueskyweb.app.Share-with-Bluesky',
+ entitlements: {
+ 'com.apple.security.application-groups': [
+ 'group.app.bsky',
+ ],
+ },
+ },
+ ],
+ },
+ },
+ },
projectId: '55bd077a-d905-4184-9c7f-94789ba0f302',
},
},
diff --git a/assets/icons/checkThick_stroke2_corner0_rounded.svg b/assets/icons/checkThick_stroke2_corner0_rounded.svg
new file mode 100644
index 0000000000..54af3e8598
--- /dev/null
+++ b/assets/icons/checkThick_stroke2_corner0_rounded.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/clipboard_stroke2_corner2_rounded.svg b/assets/icons/clipboard_stroke2_corner2_rounded.svg
new file mode 100644
index 0000000000..f403cfb929
--- /dev/null
+++ b/assets/icons/clipboard_stroke2_corner2_rounded.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/magnifyingGlass2_stroke2_corner0_rounded.svg b/assets/icons/magnifyingGlass2_stroke2_corner0_rounded.svg
new file mode 100644
index 0000000000..2759aaf2cc
--- /dev/null
+++ b/assets/icons/magnifyingGlass2_stroke2_corner0_rounded.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/mute_stroke2_corner0_rounded.svg b/assets/icons/mute_stroke2_corner0_rounded.svg
new file mode 100644
index 0000000000..8ebecb3920
--- /dev/null
+++ b/assets/icons/mute_stroke2_corner0_rounded.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/pageText_stroke2_corner0_rounded.svg b/assets/icons/pageText_stroke2_corner0_rounded.svg
new file mode 100644
index 0000000000..826a36cd7e
--- /dev/null
+++ b/assets/icons/pageText_stroke2_corner0_rounded.svg
@@ -0,0 +1 @@
+
diff --git a/bskyweb/README.md b/bskyweb/README.md
index c8efe04482..640c30f4ad 100644
--- a/bskyweb/README.md
+++ b/bskyweb/README.md
@@ -6,9 +6,9 @@ To build the SPA bundle (`bundle.web.js`), first get a JavaScript development
environment set up. Either follow the top-level README, or something quick
like:
- # install nodejs 18 (specifically)
- nvm install 18
- nvm use 18
+ # install nodejs
+ nvm install
+ nvm use
npm install --global yarn
# setup tools and deps (in top level of this repo)
diff --git a/bskyweb/cmd/bskyweb/mailmodo.go b/bskyweb/cmd/bskyweb/mailmodo.go
deleted file mode 100644
index e892971f9c..0000000000
--- a/bskyweb/cmd/bskyweb/mailmodo.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package main
-
-import (
- "bytes"
- "context"
- "crypto/sha256"
- "encoding/json"
- "fmt"
- "net/http"
- "time"
-)
-
-type Mailmodo struct {
- httpClient *http.Client
- APIKey string
- BaseURL string
- ListName string
-}
-
-func NewMailmodo(apiKey, listName string) *Mailmodo {
- return &Mailmodo{
- APIKey: apiKey,
- BaseURL: "https://api.mailmodo.com/api/v1",
- httpClient: &http.Client{},
- ListName: listName,
- }
-}
-
-func (m *Mailmodo) request(ctx context.Context, httpMethod string, apiMethod string, data any) error {
- endpoint := fmt.Sprintf("%s/%s", m.BaseURL, apiMethod)
- js, err := json.Marshal(data)
- if err != nil {
- return fmt.Errorf("Mailmodo JSON encoding failed: %w", err)
- }
- req, err := http.NewRequestWithContext(ctx, httpMethod, endpoint, bytes.NewBuffer(js))
- if err != nil {
- return fmt.Errorf("Mailmodo HTTP creating request %s %s failed: %w", httpMethod, apiMethod, err)
- }
- req.Header.Set("mmApiKey", m.APIKey)
- req.Header.Set("Content-Type", "application/json")
-
- res, err := m.httpClient.Do(req)
- if err != nil {
- return fmt.Errorf("Mailmodo HTTP making request %s %s failed: %w", httpMethod, apiMethod, err)
- }
- defer res.Body.Close()
-
- status := struct {
- Success bool `json:"success"`
- Message string `json:"message"`
- }{}
- if err := json.NewDecoder(res.Body).Decode(&status); err != nil {
- return fmt.Errorf("Mailmodo HTTP parsing response %s %s failed: %w", httpMethod, apiMethod, err)
- }
- if !status.Success {
- return fmt.Errorf("Mailmodo API response %s %s failed: %s", httpMethod, apiMethod, status.Message)
- }
- return nil
-}
-
-func (m *Mailmodo) AddToList(ctx context.Context, email string) error {
- return m.request(ctx, "POST", "addToList", map[string]any{
- "listName": m.ListName,
- "email": email,
- "data": map[string]any{
- "email_hashed": fmt.Sprintf("%x", sha256.Sum256([]byte(email))),
- },
- "created_at": time.Now().UTC().Format(time.RFC3339),
- })
-}
diff --git a/bskyweb/cmd/bskyweb/main.go b/bskyweb/cmd/bskyweb/main.go
index a2952cae2b..5185ff573a 100644
--- a/bskyweb/cmd/bskyweb/main.go
+++ b/bskyweb/cmd/bskyweb/main.go
@@ -40,18 +40,6 @@ func run(args []string) {
// retain old PDS env var for easy transition
EnvVars: []string{"ATP_APPVIEW_HOST", "ATP_PDS_HOST"},
},
- &cli.StringFlag{
- Name: "mailmodo-api-key",
- Usage: "Mailmodo API key",
- Required: false,
- EnvVars: []string{"MAILMODO_API_KEY"},
- },
- &cli.StringFlag{
- Name: "mailmodo-list-name",
- Usage: "Mailmodo contact list to add email addresses to",
- Required: false,
- EnvVars: []string{"MAILMODO_LIST_NAME"},
- },
&cli.StringFlag{
Name: "http-address",
Usage: "Specify the local IP/port to bind to",
diff --git a/bskyweb/cmd/bskyweb/server.go b/bskyweb/cmd/bskyweb/server.go
index 4b1a824935..d30781b9ce 100644
--- a/bskyweb/cmd/bskyweb/server.go
+++ b/bskyweb/cmd/bskyweb/server.go
@@ -2,11 +2,9 @@ package main
import (
"context"
- "encoding/json"
"errors"
"fmt"
"io/fs"
- "io/ioutil"
"net/http"
"os"
"os/signal"
@@ -29,25 +27,19 @@ import (
)
type Server struct {
- echo *echo.Echo
- httpd *http.Server
- mailmodo *Mailmodo
- xrpcc *xrpc.Client
+ echo *echo.Echo
+ httpd *http.Server
+ xrpcc *xrpc.Client
}
func serve(cctx *cli.Context) error {
debug := cctx.Bool("debug")
httpAddress := cctx.String("http-address")
appviewHost := cctx.String("appview-host")
- mailmodoAPIKey := cctx.String("mailmodo-api-key")
- mailmodoListName := cctx.String("mailmodo-list-name")
// Echo
e := echo.New()
- // Mailmodo client.
- mailmodo := NewMailmodo(mailmodoAPIKey, mailmodoListName)
-
// create a new session (no auth)
xrpcc := &xrpc.Client{
Client: cliutil.NewHttpClient(),
@@ -77,9 +69,8 @@ func serve(cctx *cli.Context) error {
// server
//
server := &Server{
- echo: e,
- mailmodo: mailmodo,
- xrpcc: xrpcc,
+ echo: e,
+ xrpcc: xrpcc,
}
// Create the HTTP server.
@@ -180,6 +171,7 @@ func serve(cctx *cli.Context) error {
e.GET("/", server.WebHome)
// generic routes
+ e.GET("/hashtag/:tag", server.WebGeneric)
e.GET("/search", server.WebGeneric)
e.GET("/feeds", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
@@ -203,6 +195,7 @@ func serve(cctx *cli.Context) error {
e.GET("/support/tos", server.WebGeneric)
e.GET("/support/community-guidelines", server.WebGeneric)
e.GET("/support/copyright", server.WebGeneric)
+ e.GET("/intent/compose", server.WebGeneric)
// profile endpoints; only first populates info
e.GET("/profile/:handleOrDID", server.WebProfile)
@@ -220,9 +213,6 @@ func serve(cctx *cli.Context) error {
e.GET("/profile/:handleOrDID/post/:rkey/liked-by", server.WebGeneric)
e.GET("/profile/:handleOrDID/post/:rkey/reposted-by", server.WebGeneric)
- // Mailmodo
- e.POST("/api/waitlist", server.apiWaitlist)
-
// Start the server.
log.Infof("starting server address=%s", httpAddress)
go func() {
@@ -397,36 +387,3 @@ func (srv *Server) WebProfile(c echo.Context) error {
data["requestHost"] = req.Host
return c.Render(http.StatusOK, "profile.html", data)
}
-
-func (srv *Server) apiWaitlist(c echo.Context) error {
- type jsonError struct {
- Error string `json:"error"`
- }
-
- // Read the API request.
- type apiRequest struct {
- Email string `json:"email"`
- }
-
- bodyReader := http.MaxBytesReader(c.Response(), c.Request().Body, 16*1024)
- payload, err := ioutil.ReadAll(bodyReader)
- if err != nil {
- return err
- }
- var req apiRequest
- if err := json.Unmarshal(payload, &req); err != nil {
- return c.JSON(http.StatusBadRequest, jsonError{Error: "Invalid API request"})
- }
-
- if req.Email == "" {
- return c.JSON(http.StatusBadRequest, jsonError{Error: "Please enter a valid email address."})
- }
-
- if err := srv.mailmodo.AddToList(c.Request().Context(), req.Email); err != nil {
- log.Errorf("adding email to waitlist failed: %s", err)
- return c.JSON(http.StatusBadRequest, jsonError{
- Error: "Storing email in waitlist failed. Please enter a valid email address.",
- })
- }
- return c.JSON(http.StatusOK, map[string]bool{"success": true})
-}
diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html
index e29e4032bb..55447552ea 100644
--- a/bskyweb/templates/base.html
+++ b/bskyweb/templates/base.html
@@ -44,6 +44,12 @@
scrollbar-gutter: stable both-edges;
}
+ /* Buttons and inputs have a font set by UA, so we'll have to reset that */
+ button, input, textarea {
+ font: inherit;
+ line-height: inherit;
+ }
+
/* Color theming */
/* Default will always be white */
:root {
@@ -205,6 +211,12 @@
[data-tooltip]:hover::before {
display:block;
}
+
+ /* NativeDropdown component */
+ .radix-dropdown-item:focus,
+ .nativeDropdown-item:focus {
+ outline: none;
+ }
{% include "scripts.html" %}
diff --git a/index.web.js b/index.web.js
index 4dee831cda..9623734512 100644
--- a/index.web.js
+++ b/index.web.js
@@ -1,3 +1,5 @@
+import '#/platform/markBundleStartTime'
+
import '#/platform/polyfills'
import {registerRootComponent} from 'expo'
import {doPolyfill} from '#/lib/api/api-polyfill'
diff --git a/modules/Share-with-Bluesky/Info.plist b/modules/Share-with-Bluesky/Info.plist
new file mode 100644
index 0000000000..90fe923455
--- /dev/null
+++ b/modules/Share-with-Bluesky/Info.plist
@@ -0,0 +1,41 @@
+
+
+
+
+ NSExtension
+
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).ShareViewController
+ NSExtensionAttributes
+
+ NSExtensionActivationRule
+
+ NSExtensionActivationSupportsText
+
+ NSExtensionActivationSupportsWebURLWithMaxCount
+ 1
+ NSExtensionActivationSupportsImageWithMaxCount
+ 10
+
+
+ NSExtensionPointIdentifier
+ com.apple.share-services
+
+ MainAppScheme
+ bluesky
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundleDisplayName
+ Extension
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+
+
diff --git a/modules/Share-with-Bluesky/Share-with-Bluesky.entitlements b/modules/Share-with-Bluesky/Share-with-Bluesky.entitlements
new file mode 100644
index 0000000000..d2253d31f8
--- /dev/null
+++ b/modules/Share-with-Bluesky/Share-with-Bluesky.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.app.bsky
+
+
+
diff --git a/modules/Share-with-Bluesky/ShareViewController.swift b/modules/Share-with-Bluesky/ShareViewController.swift
new file mode 100644
index 0000000000..4c1d635ce3
--- /dev/null
+++ b/modules/Share-with-Bluesky/ShareViewController.swift
@@ -0,0 +1,153 @@
+import UIKit
+
+class ShareViewController: UIViewController {
+ // This allows other forks to use this extension while also changing their
+ // scheme.
+ let appScheme = Bundle.main.object(forInfoDictionaryKey: "MainAppScheme") as? String ?? "bluesky"
+
+ //
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+
+ guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem,
+ let attachments = extensionItem.attachments,
+ let firstAttachment = extensionItem.attachments?.first
+ else {
+ self.completeRequest()
+ return
+ }
+
+ Task {
+ if firstAttachment.hasItemConformingToTypeIdentifier("public.text") {
+ await self.handleText(item: firstAttachment)
+ } else if firstAttachment.hasItemConformingToTypeIdentifier("public.url") {
+ await self.handleUrl(item: firstAttachment)
+ } else if firstAttachment.hasItemConformingToTypeIdentifier("public.image") {
+ await self.handleImages(items: attachments)
+ } else {
+ self.completeRequest()
+ }
+ }
+ }
+
+ private func handleText(item: NSItemProvider) async -> Void {
+ do {
+ if let data = try await item.loadItem(forTypeIdentifier: "public.text") as? String {
+ if let encoded = data.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
+ let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)")
+ {
+ _ = self.openURL(url)
+ }
+ }
+ self.completeRequest()
+ } catch {
+ self.completeRequest()
+ }
+ }
+
+ private func handleUrl(item: NSItemProvider) async -> Void {
+ do {
+ if let data = try await item.loadItem(forTypeIdentifier: "public.url") as? URL {
+ if let encoded = data.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
+ let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)")
+ {
+ _ = self.openURL(url)
+ }
+ }
+ self.completeRequest()
+ } catch {
+ self.completeRequest()
+ }
+ }
+
+ private func handleImages(items: [NSItemProvider]) async -> Void {
+ let firstFourItems: [NSItemProvider]
+ if items.count < 4 {
+ firstFourItems = items
+ } else {
+ firstFourItems = Array(items[0...3])
+ }
+
+ var valid = true
+ var imageUris = ""
+
+ for (index, item) in firstFourItems.enumerated() {
+ var imageUriInfo: String? = nil
+
+ do {
+ if let dataUri = try await item.loadItem(forTypeIdentifier: "public.image") as? URL {
+ // We need to duplicate this image, since we don't have access to the outgoing temp directory
+ // We also will get the image dimensions here, sinze RN makes it difficult to get those dimensions for local files
+ let data = try Data(contentsOf: dataUri)
+ let image = UIImage(data: data)
+ imageUriInfo = self.saveImageWithInfo(image)
+ } else if let image = try await item.loadItem(forTypeIdentifier: "public.image") as? UIImage {
+ imageUriInfo = self.saveImageWithInfo(image)
+ }
+ } catch {
+ valid = false
+ }
+
+ if let imageUriInfo = imageUriInfo {
+ imageUris.append(imageUriInfo)
+ if index < items.count - 1 {
+ imageUris.append(",")
+ }
+ } else {
+ valid = false
+ }
+ }
+
+ if valid,
+ let encoded = imageUris.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
+ let url = URL(string: "\(self.appScheme)://intent/compose?imageUris=\(encoded)")
+ {
+ _ = self.openURL(url)
+ }
+
+ self.completeRequest()
+ }
+
+ private func saveImageWithInfo(_ image: UIImage?) -> String? {
+ guard let image = image else {
+ return nil
+ }
+
+ do {
+ // Saving this file to the bundle group's directory lets us access it from
+ // inside of the app. Otherwise, we wouldn't have access even though the
+ // extension does.
+ if let dir = FileManager()
+ .containerURL(
+ forSecurityApplicationGroupIdentifier: "group.app.bsky")
+ {
+ let filePath = "\(dir.absoluteString)\(ProcessInfo.processInfo.globallyUniqueString).jpeg"
+
+ if let newUri = URL(string: filePath),
+ let jpegData = image.jpegData(compressionQuality: 1)
+ {
+ try jpegData.write(to: newUri)
+ return "\(newUri.absoluteString)|\(image.size.width)|\(image.size.height)"
+ }
+ }
+ return nil
+ } catch {
+ return nil
+ }
+ }
+
+ private func completeRequest() -> Void {
+ self.extensionContext?.completeRequest(returningItems: nil)
+ }
+
+ @objc func openURL(_ url: URL) -> Bool {
+ var responder: UIResponder? = self
+ while responder != nil {
+ if let application = responder as? UIApplication {
+ return application.perform(#selector(openURL(_:)), with: url) != nil
+ }
+ responder = responder?.next
+ }
+ return false
+ }
+}
diff --git a/modules/expo-receive-android-intents/README.md b/modules/expo-receive-android-intents/README.md
new file mode 100644
index 0000000000..7e8506860c
--- /dev/null
+++ b/modules/expo-receive-android-intents/README.md
@@ -0,0 +1,8 @@
+# Expo Receive Android Intents
+
+This module handles incoming intents on Android. Handled intents are `text/plain` and `image/*` (single or multiple).
+The module handles saving images to the app's filesystem for access within the app, limiting the selection of images
+to a max of four, and handling intent types. No JS code is required for this module, and it is no-op on non-android
+platforms.
+
+No installation is required. Gradle will automatically add this module on build.
diff --git a/modules/expo-receive-android-intents/android/.gitignore b/modules/expo-receive-android-intents/android/.gitignore
new file mode 100644
index 0000000000..877b87e9a5
--- /dev/null
+++ b/modules/expo-receive-android-intents/android/.gitignore
@@ -0,0 +1,15 @@
+# OSX
+#
+.DS_Store
+
+# Android/IntelliJ
+#
+build/
+.idea
+.gradle
+local.properties
+*.iml
+*.hprof
+
+# Bundle artifacts
+*.jsbundle
diff --git a/modules/expo-receive-android-intents/android/build.gradle b/modules/expo-receive-android-intents/android/build.gradle
new file mode 100644
index 0000000000..3712dda40f
--- /dev/null
+++ b/modules/expo-receive-android-intents/android/build.gradle
@@ -0,0 +1,92 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'maven-publish'
+
+group = 'xyz.blueskyweb.app.exporeceiveandroidintents'
+version = '0.4.1'
+
+buildscript {
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
+ if (expoModulesCorePlugin.exists()) {
+ apply from: expoModulesCorePlugin
+ applyKotlinExpoModulesCorePlugin()
+ }
+
+ // Simple helper that allows the root project to override versions declared by this library.
+ ext.safeExtGet = { prop, fallback ->
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+ }
+
+ // Ensures backward compatibility
+ ext.getKotlinVersion = {
+ if (ext.has("kotlinVersion")) {
+ ext.kotlinVersion()
+ } else {
+ ext.safeExtGet("kotlinVersion", "1.8.10")
+ }
+ }
+
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
+ }
+}
+
+afterEvaluate {
+ publishing {
+ publications {
+ release(MavenPublication) {
+ from components.release
+ }
+ }
+ repositories {
+ maven {
+ url = mavenLocal().url
+ }
+ }
+ }
+}
+
+android {
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
+
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
+ if (agpVersion.tokenize('.')[0].toInteger() < 8) {
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_11
+ targetCompatibility JavaVersion.VERSION_11
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_11.majorVersion
+ }
+ }
+
+ namespace "xyz.blueskyweb.app.exporeceiveandroidintents"
+ defaultConfig {
+ minSdkVersion safeExtGet("minSdkVersion", 21)
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
+ versionCode 1
+ versionName "0.4.1"
+ }
+ lintOptions {
+ abortOnError false
+ }
+ publishing {
+ singleVariant("release") {
+ withSourcesJar()
+ }
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation project(':expo-modules-core')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
+}
diff --git a/modules/expo-receive-android-intents/android/src/main/AndroidManifest.xml b/modules/expo-receive-android-intents/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..bdae66c8f5
--- /dev/null
+++ b/modules/expo-receive-android-intents/android/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt b/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt
new file mode 100644
index 0000000000..c2e17fb80a
--- /dev/null
+++ b/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt
@@ -0,0 +1,119 @@
+package xyz.blueskyweb.app.exporeceiveandroidintents
+
+import android.content.Intent
+import android.graphics.Bitmap
+import android.net.Uri
+import android.os.Build
+import android.provider.MediaStore
+import androidx.core.net.toUri
+import expo.modules.kotlin.modules.Module
+import expo.modules.kotlin.modules.ModuleDefinition
+import java.io.File
+import java.io.FileOutputStream
+import java.net.URLEncoder
+
+class ExpoReceiveAndroidIntentsModule : Module() {
+ override fun definition() = ModuleDefinition {
+ Name("ExpoReceiveAndroidIntents")
+
+ OnNewIntent {
+ handleIntent(it)
+ }
+ }
+
+ private fun handleIntent(intent: Intent?) {
+ if(appContext.currentActivity == null || intent == null) return
+
+ if (intent.action == Intent.ACTION_SEND) {
+ if (intent.type == "text/plain") {
+ handleTextIntent(intent)
+ } else if (intent.type.toString().startsWith("image/")) {
+ handleImageIntent(intent)
+ }
+ } else if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
+ if (intent.type.toString().startsWith("image/")) {
+ handleImagesIntent(intent)
+ }
+ }
+ }
+
+ private fun handleTextIntent(intent: Intent) {
+ intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
+ val encoded = URLEncoder.encode(it, "UTF-8")
+ "bluesky://intent/compose?text=${encoded}".toUri().let { uri ->
+ val newIntent = Intent(Intent.ACTION_VIEW, uri)
+ appContext.currentActivity?.startActivity(newIntent)
+ }
+ }
+ }
+
+ private fun handleImageIntent(intent: Intent) {
+ val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
+ } else {
+ intent.getParcelableExtra(Intent.EXTRA_STREAM)
+ }
+ if (uri == null) return
+
+ handleImageIntents(listOf(uri))
+ }
+
+ private fun handleImagesIntent(intent: Intent) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
+ handleImageIntents(it.filterIsInstance().take(4))
+ }
+ } else {
+ intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)?.let {
+ handleImageIntents(it.filterIsInstance().take(4))
+ }
+ }
+ }
+
+ private fun handleImageIntents(uris: List) {
+ var allParams = ""
+
+ uris.forEachIndexed { index, uri ->
+ val info = getImageInfo(uri)
+ val params = buildUriData(info)
+ allParams = "${allParams}${params}"
+
+ if (index < uris.count() - 1) {
+ allParams = "${allParams},"
+ }
+ }
+
+ val encoded = URLEncoder.encode(allParams, "UTF-8")
+
+ "bluesky://intent/compose?imageUris=${encoded}".toUri().let {
+ val newIntent = Intent(Intent.ACTION_VIEW, it)
+ appContext.currentActivity?.startActivity(newIntent)
+ }
+ }
+
+ private fun getImageInfo(uri: Uri): Map {
+ val bitmap = MediaStore.Images.Media.getBitmap(appContext.currentActivity?.contentResolver, uri)
+ // We have to save this so that we can access it later when uploading the image.
+ // createTempFile will automatically place a unique string between "img" and "temp.jpeg"
+ val file = File.createTempFile("img", "temp.jpeg", appContext.currentActivity?.cacheDir)
+ val out = FileOutputStream(file)
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
+ out.flush()
+ out.close()
+
+ return mapOf(
+ "width" to bitmap.width,
+ "height" to bitmap.height,
+ "path" to file.path.toString()
+ )
+ }
+
+ // We will pas the width and height to the app here, since getting measurements
+ // on the RN side is a bit more involved, and we already have them here anyway.
+ private fun buildUriData(info: Map): String {
+ val path = info.getValue("path")
+ val width = info.getValue("width")
+ val height = info.getValue("height")
+ return "file://${path}|${width}|${height}"
+ }
+}
diff --git a/modules/expo-receive-android-intents/expo-module.config.json b/modules/expo-receive-android-intents/expo-module.config.json
new file mode 100644
index 0000000000..8f01fb6c9f
--- /dev/null
+++ b/modules/expo-receive-android-intents/expo-module.config.json
@@ -0,0 +1,6 @@
+{
+ "platforms": ["android"],
+ "android": {
+ "modules": ["xyz.blueskyweb.app.exporeceiveandroidintents.ExpoReceiveAndroidIntentsModule"]
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/RNUITextView.swift b/modules/react-native-ui-text-view/ios/RNUITextView.swift
index 9c21d45b5e..3fb55873dc 100644
--- a/modules/react-native-ui-text-view/ios/RNUITextView.swift
+++ b/modules/react-native-ui-text-view/ios/RNUITextView.swift
@@ -108,14 +108,26 @@ class RNUITextView: UIView {
fractionOfDistanceBetweenInsertionPoints: nil
)
+ var lastUpperBound: String.Index? = nil
for child in self.reactSubviews() {
if let child = child as? RNUITextViewChild, let childText = child.text {
let fullText = self.textView.attributedText.string
- let range = fullText.range(of: childText)
-
+
+ // We want to skip over the children we have already checked, otherwise we could run into
+ // collisions of similar strings (i.e. links that get shortened to the same hostname but
+ // different paths)
+ let range = fullText.range(of: childText, options: [], range: (lastUpperBound ?? String.Index(utf16Offset: 0, in: fullText) )..= lowerBound.utf16Offset(in: fullText) && charIndex <= upperBound.utf16Offset(in: fullText) {
+ let lowerOffset = lowerBound.utf16Offset(in: fullText)
+ let upperOffset = upperBound.utf16Offset(in: fullText)
+
+ if charIndex >= lowerOffset,
+ charIndex <= upperOffset
+ {
return child
+ } else {
+ lastUpperBound = upperBound
}
}
}
diff --git a/package.json b/package.json
index 14b1e2f908..bb3aaca372 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bsky.app",
- "version": "1.69.0",
+ "version": "1.72.0",
"private": true,
"engines": {
"node": ">=18"
@@ -36,14 +36,15 @@
"perf:test:measure": "NODE_ENV=test flashlight test --bundleId xyz.blueskyweb.app --testCommand 'yarn perf:test' --duration 150000 --resultsFilePath .perf/results.json",
"perf:test:results": "NODE_ENV=test flashlight report .perf/results.json",
"perf:measure": "NODE_ENV=test flashlight measure",
- "intl:build": "yarn intl:check && yarn intl:compile",
+ "intl:build": "yarn intl:extract && yarn intl:compile",
"intl:check": "yarn intl:extract && git diff-index -G'(^[^\\*# /])|(^#\\w)|(^\\s+[^\\*#/])' HEAD || (echo '\nā ļø i18n detected un-extracted translations\n' && exit 1)",
"intl:extract": "lingui extract",
"intl:compile": "lingui compile",
- "nuke": "rm -rf ./node_modules && rm -rf ./ios && rm -rf ./android"
+ "nuke": "rm -rf ./node_modules && rm -rf ./ios && rm -rf ./android",
+ "update-extensions": "scripts/updateExtensions.sh"
},
"dependencies": {
- "@atproto/api": "^0.9.5",
+ "@atproto/api": "^0.10.5",
"@bam.tech/react-native-image-resizer": "^3.0.4",
"@braintree/sanitize-url": "^6.0.2",
"@emoji-mart/react": "^1.1.1",
@@ -57,11 +58,11 @@
"@lingui/react": "^4.5.0",
"@mattermost/react-native-paste-input": "^0.6.4",
"@miblanchard/react-native-slider": "^2.3.1",
+ "@radix-ui/react-dropdown-menu": "^2.0.6",
"@react-native-async-storage/async-storage": "1.21.0",
"@react-native-camera-roll/camera-roll": "^5.2.2",
"@react-native-clipboard/clipboard": "^1.10.0",
"@react-native-community/blur": "^4.3.0",
- "@react-native-community/datetimepicker": "7.6.1",
"@react-native-masked-view/masked-view": "0.3.0",
"@react-native-menu/menu": "^0.8.0",
"@react-native-picker/picker": "2.6.1",
@@ -111,6 +112,7 @@
"expo-image": "~1.10.3",
"expo-image-manipulator": "^11.8.0",
"expo-image-picker": "~14.7.1",
+ "expo-linking": "^6.2.2",
"expo-localization": "~14.8.2",
"expo-media-library": "~15.9.1",
"expo-notifications": "~0.27.3",
@@ -148,8 +150,10 @@
"react-avatar-editor": "^13.0.0",
"react-circular-progressbar": "^2.1.0",
"react-dom": "^18.2.0",
+ "react-keyed-flatten-children": "^3.0.0",
"react-native": "0.73.2",
"react-native-appstate-hook": "^1.0.6",
+ "react-native-date-picker": "^4.4.0",
"react-native-drawer-layout": "^4.0.0-alpha.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.14.0",
@@ -177,6 +181,8 @@
"react-responsive": "^9.0.2",
"rn-fetch-blob": "^0.12.0",
"sentry-expo": "~7.0.1",
+ "statsig-react": "^1.36.0",
+ "statsig-react-native-expo": "^4.6.1",
"tippy.js": "^6.3.7",
"tlds": "^1.234.0",
"use-deep-compare": "^1.1.0",
diff --git a/plugins/shareExtension/README.md b/plugins/shareExtension/README.md
new file mode 100644
index 0000000000..2b57e624ae
--- /dev/null
+++ b/plugins/shareExtension/README.md
@@ -0,0 +1,22 @@
+# Share extension plugin for Expo
+
+This plugin handles moving the necessary files into their respective iOS and Android targets and updating the build
+phases, plists, manifests, etc.
+
+## Steps
+
+### ios
+
+1. Update entitlements
+2. Set the app group to group.
+3. Add the extension plist
+4. Add the view controller
+5. Update the xcode project's build phases
+
+### android
+
+1. Update the manifest with the intents the app can receive
+
+## Credits
+
+Adapted from https://github.com/andrew-levy/react-native-safari-extension and https://github.com/timedtext/expo-config-plugin-ios-share-extension/blob/master/src/withShareExtensionXcodeTarget.ts
diff --git a/plugins/shareExtension/withAppEntitlements.js b/plugins/shareExtension/withAppEntitlements.js
new file mode 100644
index 0000000000..4ce81ea611
--- /dev/null
+++ b/plugins/shareExtension/withAppEntitlements.js
@@ -0,0 +1,13 @@
+const {withEntitlementsPlist} = require('@expo/config-plugins')
+
+const withAppEntitlements = config => {
+ // eslint-disable-next-line no-shadow
+ return withEntitlementsPlist(config, async config => {
+ config.modResults['com.apple.security.application-groups'] = [
+ `group.app.bsky`,
+ ]
+ return config
+ })
+}
+
+module.exports = {withAppEntitlements}
diff --git a/plugins/shareExtension/withExtensionEntitlements.js b/plugins/shareExtension/withExtensionEntitlements.js
new file mode 100644
index 0000000000..7bee79d1a6
--- /dev/null
+++ b/plugins/shareExtension/withExtensionEntitlements.js
@@ -0,0 +1,31 @@
+const {withInfoPlist} = require('@expo/config-plugins')
+const plist = require('@expo/plist')
+const path = require('path')
+const fs = require('fs')
+
+const withExtensionEntitlements = (config, {extensionName}) => {
+ // eslint-disable-next-line no-shadow
+ return withInfoPlist(config, config => {
+ const extensionEntitlementsPath = path.join(
+ config.modRequest.platformProjectRoot,
+ extensionName,
+ `${extensionName}.entitlements`,
+ )
+
+ const shareExtensionEntitlements = {
+ 'com.apple.security.application-groups': [`group.app.bsky`],
+ }
+
+ fs.mkdirSync(path.dirname(extensionEntitlementsPath), {
+ recursive: true,
+ })
+ fs.writeFileSync(
+ extensionEntitlementsPath,
+ plist.default.build(shareExtensionEntitlements),
+ )
+
+ return config
+ })
+}
+
+module.exports = {withExtensionEntitlements}
diff --git a/plugins/shareExtension/withExtensionInfoPlist.js b/plugins/shareExtension/withExtensionInfoPlist.js
new file mode 100644
index 0000000000..9afc4d5f92
--- /dev/null
+++ b/plugins/shareExtension/withExtensionInfoPlist.js
@@ -0,0 +1,39 @@
+const {withInfoPlist} = require('@expo/config-plugins')
+const plist = require('@expo/plist')
+const path = require('path')
+const fs = require('fs')
+
+const withExtensionInfoPlist = (config, {extensionName}) => {
+ // eslint-disable-next-line no-shadow
+ return withInfoPlist(config, config => {
+ const plistPath = path.join(
+ config.modRequest.projectRoot,
+ 'modules',
+ extensionName,
+ 'Info.plist',
+ )
+ const targetPath = path.join(
+ config.modRequest.platformProjectRoot,
+ extensionName,
+ 'Info.plist',
+ )
+
+ const extPlist = plist.default.parse(fs.readFileSync(plistPath).toString())
+
+ extPlist.MainAppScheme = config.scheme
+ extPlist.CFBundleName = '$(PRODUCT_NAME)'
+ extPlist.CFBundleDisplayName = 'Extension'
+ extPlist.CFBundleIdentifier = '$(PRODUCT_BUNDLE_IDENTIFIER)'
+ extPlist.CFBundleVersion = '$(CURRENT_PROJECT_VERSION)'
+ extPlist.CFBundleExecutable = '$(EXECUTABLE_NAME)'
+ extPlist.CFBundlePackageType = '$(PRODUCT_BUNDLE_PACKAGE_TYPE)'
+ extPlist.CFBundleShortVersionString = '$(MARKETING_VERSION)'
+
+ fs.mkdirSync(path.dirname(targetPath), {recursive: true})
+ fs.writeFileSync(targetPath, plist.default.build(extPlist))
+
+ return config
+ })
+}
+
+module.exports = {withExtensionInfoPlist}
diff --git a/plugins/shareExtension/withExtensionViewController.js b/plugins/shareExtension/withExtensionViewController.js
new file mode 100644
index 0000000000..cd29bea7da
--- /dev/null
+++ b/plugins/shareExtension/withExtensionViewController.js
@@ -0,0 +1,31 @@
+const {withXcodeProject} = require('@expo/config-plugins')
+const path = require('path')
+const fs = require('fs')
+
+const withExtensionViewController = (
+ config,
+ {controllerName, extensionName},
+) => {
+ // eslint-disable-next-line no-shadow
+ return withXcodeProject(config, config => {
+ const controllerPath = path.join(
+ config.modRequest.projectRoot,
+ 'modules',
+ extensionName,
+ `${controllerName}.swift`,
+ )
+
+ const targetPath = path.join(
+ config.modRequest.platformProjectRoot,
+ extensionName,
+ `${controllerName}.swift`,
+ )
+
+ fs.mkdirSync(path.dirname(targetPath), {recursive: true})
+ fs.copyFileSync(controllerPath, targetPath)
+
+ return config
+ })
+}
+
+module.exports = {withExtensionViewController}
diff --git a/plugins/shareExtension/withIntentFilters.js b/plugins/shareExtension/withIntentFilters.js
new file mode 100644
index 0000000000..605fcfd052
--- /dev/null
+++ b/plugins/shareExtension/withIntentFilters.js
@@ -0,0 +1,89 @@
+const {withAndroidManifest} = require('@expo/config-plugins')
+
+const withIntentFilters = config => {
+ // eslint-disable-next-line no-shadow
+ return withAndroidManifest(config, config => {
+ const intents = [
+ {
+ action: [
+ {
+ $: {
+ 'android:name': 'android.intent.action.SEND',
+ },
+ },
+ ],
+ category: [
+ {
+ $: {
+ 'android:name': 'android.intent.category.DEFAULT',
+ },
+ },
+ ],
+ data: [
+ {
+ $: {
+ 'android:mimeType': 'image/*',
+ },
+ },
+ ],
+ },
+ {
+ action: [
+ {
+ $: {
+ 'android:name': 'android.intent.action.SEND',
+ },
+ },
+ ],
+ category: [
+ {
+ $: {
+ 'android:name': 'android.intent.category.DEFAULT',
+ },
+ },
+ ],
+ data: [
+ {
+ $: {
+ 'android:mimeType': 'text/plain',
+ },
+ },
+ ],
+ },
+ {
+ action: [
+ {
+ $: {
+ 'android:name': 'android.intent.action.SEND_MULTIPLE',
+ },
+ },
+ ],
+ category: [
+ {
+ $: {
+ 'android:name': 'android.intent.category.DEFAULT',
+ },
+ },
+ ],
+ data: [
+ {
+ $: {
+ 'android:mimeType': 'image/*',
+ },
+ },
+ ],
+ },
+ ]
+
+ const intentFilter =
+ config.modResults.manifest.application?.[0].activity?.[0]['intent-filter']
+
+ if (intentFilter) {
+ intentFilter.push(...intents)
+ }
+
+ return config
+ })
+}
+
+module.exports = {withIntentFilters}
diff --git a/plugins/shareExtension/withShareExtensions.js b/plugins/shareExtension/withShareExtensions.js
new file mode 100644
index 0000000000..55a26c75eb
--- /dev/null
+++ b/plugins/shareExtension/withShareExtensions.js
@@ -0,0 +1,47 @@
+const {withPlugins} = require('@expo/config-plugins')
+const {withAppEntitlements} = require('./withAppEntitlements')
+const {withXcodeTarget} = require('./withXcodeTarget')
+const {withExtensionEntitlements} = require('./withExtensionEntitlements')
+const {withExtensionInfoPlist} = require('./withExtensionInfoPlist')
+const {withExtensionViewController} = require('./withExtensionViewController')
+const {withIntentFilters} = require('./withIntentFilters')
+
+const SHARE_EXTENSION_NAME = 'Share-with-Bluesky'
+const SHARE_EXTENSION_CONTROLLER_NAME = 'ShareViewController'
+
+const withShareExtensions = config => {
+ return withPlugins(config, [
+ // IOS
+ withAppEntitlements,
+ [
+ withExtensionEntitlements,
+ {
+ extensionName: SHARE_EXTENSION_NAME,
+ },
+ ],
+ [
+ withExtensionInfoPlist,
+ {
+ extensionName: SHARE_EXTENSION_NAME,
+ },
+ ],
+ [
+ withExtensionViewController,
+ {
+ extensionName: SHARE_EXTENSION_NAME,
+ controllerName: SHARE_EXTENSION_CONTROLLER_NAME,
+ },
+ ],
+ [
+ withXcodeTarget,
+ {
+ extensionName: SHARE_EXTENSION_NAME,
+ controllerName: SHARE_EXTENSION_CONTROLLER_NAME,
+ },
+ ],
+ // Android
+ withIntentFilters,
+ ])
+}
+
+module.exports = withShareExtensions
diff --git a/plugins/shareExtension/withXcodeTarget.js b/plugins/shareExtension/withXcodeTarget.js
new file mode 100644
index 0000000000..ce70b392d4
--- /dev/null
+++ b/plugins/shareExtension/withXcodeTarget.js
@@ -0,0 +1,63 @@
+const {withXcodeProject} = require('@expo/config-plugins')
+
+const withXcodeTarget = (config, {extensionName, controllerName}) => {
+ // eslint-disable-next-line no-shadow
+ return withXcodeProject(config, config => {
+ const pbxProject = config.modResults
+
+ const target = pbxProject.addTarget(
+ extensionName,
+ 'app_extension',
+ extensionName,
+ )
+ pbxProject.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid)
+ pbxProject.addBuildPhase(
+ [],
+ 'PBXResourcesBuildPhase',
+ 'Resources',
+ target.uuid,
+ )
+ const pbxGroupKey = pbxProject.pbxCreateGroup(extensionName, extensionName)
+ pbxProject.addFile(`${extensionName}/Info.plist`, pbxGroupKey)
+ pbxProject.addSourceFile(
+ `${extensionName}/${controllerName}.swift`,
+ {target: target.uuid},
+ pbxGroupKey,
+ )
+
+ var configurations = pbxProject.pbxXCBuildConfigurationSection()
+ for (var key in configurations) {
+ if (typeof configurations[key].buildSettings !== 'undefined') {
+ var buildSettingsObj = configurations[key].buildSettings
+ if (
+ typeof buildSettingsObj.PRODUCT_NAME !== 'undefined' &&
+ buildSettingsObj.PRODUCT_NAME === `"${extensionName}"`
+ ) {
+ buildSettingsObj.CLANG_ENABLE_MODULES = 'YES'
+ buildSettingsObj.INFOPLIST_FILE = `"${extensionName}/Info.plist"`
+ buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `"${extensionName}/${extensionName}.entitlements"`
+ buildSettingsObj.CODE_SIGN_STYLE = 'Automatic'
+ buildSettingsObj.CURRENT_PROJECT_VERSION = `"${config.ios?.buildNumber}"`
+ buildSettingsObj.GENERATE_INFOPLIST_FILE = 'YES'
+ buildSettingsObj.MARKETING_VERSION = `"${config.version}"`
+ buildSettingsObj.PRODUCT_BUNDLE_IDENTIFIER = `"${config.ios?.bundleIdentifier}.${extensionName}"`
+ buildSettingsObj.SWIFT_EMIT_LOC_STRINGS = 'YES'
+ buildSettingsObj.SWIFT_VERSION = '5.0'
+ buildSettingsObj.TARGETED_DEVICE_FAMILY = `"1,2"`
+ buildSettingsObj.DEVELOPMENT_TEAM = 'B3LX46C5HS'
+ }
+ }
+ }
+
+ pbxProject.addTargetAttribute(
+ 'DevelopmentTeam',
+ 'B3LX46C5HS',
+ extensionName,
+ )
+ pbxProject.addTargetAttribute('DevelopmentTeam', 'B3LX46C5HS')
+
+ return config
+ })
+}
+
+module.exports = {withXcodeTarget}
diff --git a/plugins/withAndroidManifestFCMIconPlugin.js b/plugins/withAndroidManifestFCMIconPlugin.js
new file mode 100644
index 0000000000..066a975d87
--- /dev/null
+++ b/plugins/withAndroidManifestFCMIconPlugin.js
@@ -0,0 +1,37 @@
+const {withAndroidManifest} = require('expo/config-plugins')
+
+module.exports = function withAndroidManifestFCMIconPlugin(appConfig) {
+ return withAndroidManifest(appConfig, function (decoratedAppConfig) {
+ try {
+ function addOrModifyMetaData(metaData, name, resource) {
+ const elem = metaData.find(elem => elem.$['android:name'] === name)
+ if (elem === undefined) {
+ metaData.push({
+ $: {
+ 'android:name': name,
+ 'android:resource': resource,
+ },
+ })
+ } else {
+ elem.$['android:resource'] = resource
+ }
+ }
+ const androidManifest = decoratedAppConfig.modResults.manifest
+ const metaData = androidManifest.application[0]['meta-data']
+ addOrModifyMetaData(
+ metaData,
+ 'com.google.firebase.messaging.default_notification_color',
+ '@color/notification_icon_color',
+ )
+ addOrModifyMetaData(
+ metaData,
+ 'com.google.firebase.messaging.default_notification_icon',
+ '@drawable/notification_icon',
+ )
+ return decoratedAppConfig
+ } catch (e) {
+ console.error(`withAndroidManifestFCMIconPlugin failed`, e)
+ }
+ return decoratedAppConfig
+ })
+}
diff --git a/plugins/withAndroidStylesWindowBackgroundPlugin.js b/plugins/withAndroidStylesWindowBackgroundPlugin.js
new file mode 100644
index 0000000000..427f43df07
--- /dev/null
+++ b/plugins/withAndroidStylesWindowBackgroundPlugin.js
@@ -0,0 +1,20 @@
+const {withAndroidStyles, AndroidConfig} = require('@expo/config-plugins')
+
+module.exports = function withAndroidStylesWindowBackgroundPlugin(appConfig) {
+ return withAndroidStyles(appConfig, function (decoratedAppConfig) {
+ try {
+ decoratedAppConfig.modResults = AndroidConfig.Styles.assignStylesValue(
+ decoratedAppConfig.modResults,
+ {
+ add: true,
+ parent: AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(),
+ name: 'android:windowBackground',
+ value: '@drawable/splashscreen',
+ },
+ )
+ } catch (e) {
+ console.error(`withAndroidStylesWindowBackgroundPlugin failed`, e)
+ }
+ return decoratedAppConfig
+ })
+}
diff --git a/scripts/README.md b/scripts/README.md
new file mode 100644
index 0000000000..99d6236f90
--- /dev/null
+++ b/scripts/README.md
@@ -0,0 +1,5 @@
+# Tool Scripts
+
+## updateExtensions.sh
+
+Updates the extensions in `/modules` with the current iOS/Android project changes.
diff --git a/scripts/updateExtensions.sh b/scripts/updateExtensions.sh
new file mode 100755
index 0000000000..f4e462b744
--- /dev/null
+++ b/scripts/updateExtensions.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+IOS_SHARE_EXTENSION_DIRECTORY="./ios/Share-with-Bluesky"
+MODULES_DIRECTORY="./modules"
+
+if [ ! -d $IOS_SHARE_EXTENSION_DIRECTORY ]; then
+ echo "$IOS_SHARE_EXTENSION_DIRECTORY not found inside of your iOS project."
+ exit 1
+else
+ cp -R $IOS_SHARE_EXTENSION_DIRECTORY $MODULES_DIRECTORY
+fi
diff --git a/src/App.native.tsx b/src/App.native.tsx
index c79088cebd..44b2cba156 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -47,8 +47,12 @@ import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unre
import * as persisted from '#/state/persisted'
import {Splash} from '#/Splash'
import {Provider as PortalProvider} from '#/components/Portal'
+import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {useIntentHandler} from 'lib/hooks/useIntentHandler'
+import {StatusBar} from 'expo-status-bar'
+import {isAndroid} from 'platform/detection'
SplashScreen.preventAutoHideAsync()
@@ -57,6 +61,7 @@ function InnerApp() {
const {resumeSession} = useSessionApi()
const theme = useColorModeTheme()
const {_} = useLingui()
+ useIntentHandler()
// init
useEffect(() => {
@@ -71,26 +76,29 @@ function InnerApp() {
return (
+ {isAndroid && }
-
-
-
-
- {/* All components should be within this provider */}
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {/* All components should be within this provider */}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/App.web.tsx b/src/App.web.tsx
index e2f1f07ff4..b0d5f12662 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -36,11 +36,14 @@ import {
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import * as persisted from '#/state/persisted'
import {Provider as PortalProvider} from '#/components/Portal'
+import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
+import {useIntentHandler} from 'lib/hooks/useIntentHandler'
function InnerApp() {
const {isInitialLoad, currentAccount} = useSession()
const {resumeSession} = useSessionApi()
const theme = useColorModeTheme()
+ useIntentHandler()
// init
useEffect(() => {
@@ -56,21 +59,23 @@ function InnerApp() {
-
-
-
-
- {/* All components should be within this provider */}
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {/* All components should be within this provider */}
+
+
+
+
+
+
+
+
+
+
+
)
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 728930a81b..b535b7a9aa 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -78,6 +78,8 @@ import {PreferencesExternalEmbeds} from '#/view/screens/PreferencesExternalEmbed
import {createNativeStackNavigatorWithAuth} from './view/shell/createNativeStackNavigatorWithAuth'
import {msg} from '@lingui/macro'
import {i18n, MessageDescriptor} from '@lingui/core'
+import HashtagScreen from '#/screens/Hashtag'
+import {logEvent} from './lib/statsig/statsig'
const navigationRef = createNavigationContainerRef()
@@ -268,6 +270,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
requireAuth: true,
}}
/>
+ HashtagScreen}
+ options={{title: title(msg`Hashtag`)}}
+ />
>
)
}
@@ -466,7 +473,8 @@ const FlatNavigator = () => {
*/
const LINKING = {
- prefixes: ['bsky://', 'https://bsky.app'],
+ // TODO figure out what we are going to use
+ prefixes: ['bsky://', 'bluesky://', 'https://bsky.app'],
getPathFromState(state: State) {
// find the current node in the navigation tree
@@ -485,6 +493,18 @@ const LINKING = {
getStateFromPath(path: string) {
const [name, params] = router.matchPath(path)
+
+ // Any time we receive a url that starts with `intent/` we want to ignore it here. It will be handled in the
+ // intent handler hook. We should check for the trailing slash, because if there isn't one then it isn't a valid
+ // intent
+ // On web, there is no route state that's created by default, so we should initialize it as the home route. On
+ // native, since the home tab and the home screen are defined as initial routes, we don't need to return a state
+ // since it will be created by react-navigation.
+ if (path.includes('intent/')) {
+ if (isNative) return
+ return buildStateObject('Flat', 'Home', params)
+ }
+
if (isNative) {
if (name === 'Search') {
return buildStateObject('SearchTab', 'Search', params)
@@ -503,7 +523,8 @@ const LINKING = {
},
])
} else {
- return buildStateObject('Flat', name, params)
+ const res = buildStateObject('Flat', name, params)
+ return res
}
},
}
@@ -635,11 +656,14 @@ function logModuleInitTime() {
return
}
didInit = true
+
const initMs = Math.round(
// @ts-ignore Emitted by Metro in the bundle prelude
performance.now() - global.__BUNDLE_START_TIME__,
)
console.log(`Time to first paint: ${initMs} ms`)
+ logEvent('init', initMs)
+
if (__DEV__) {
// This log is noisy, so keep false committed
const shouldLog = false
diff --git a/src/Splash.tsx b/src/Splash.tsx
index b2381f9232..42a21c0839 100644
--- a/src/Splash.tsx
+++ b/src/Splash.tsx
@@ -181,6 +181,8 @@ export function Splash(props: React.PropsWithChildren) {
const logoAnimations =
reduceMotion === true ? reducedLogoAnimation : logoAnimation
+ // special off-spec color for dark mode
+ const logoBg = isDarkMode ? '#0F1824' : '#fff'
return (
@@ -232,7 +234,7 @@ export function Splash(props: React.PropsWithChildren) {
},
]}>
@@ -253,7 +255,7 @@ export function Splash(props: React.PropsWithChildren) {
transform: [{translateY: -(insets.top / 2)}, {scale: 0.1}], // scale from 1000px to 100px
},
]}>
-
+
}>
{!isAnimationComplete && (
@@ -261,10 +263,7 @@ export function Splash(props: React.PropsWithChildren) {
style={[
StyleSheet.absoluteFillObject,
{
- backgroundColor: isDarkMode
- ? // special off-spec color for dark mode
- '#0F1824'
- : '#fff',
+ backgroundColor: logoBg,
},
]}
/>
diff --git a/src/alf/atoms.ts b/src/alf/atoms.ts
index b849010039..8a79a90294 100644
--- a/src/alf/atoms.ts
+++ b/src/alf/atoms.ts
@@ -1,3 +1,4 @@
+import {web, native} from '#/alf/util/platform'
import * as tokens from '#/alf/tokens'
export const atoms = {
@@ -113,6 +114,9 @@ export const atoms = {
flex_wrap: {
flexWrap: 'wrap',
},
+ flex_0: {
+ flex: web('0 0 auto') || (native(0) as number),
+ },
flex_1: {
flex: 1,
},
diff --git a/src/alf/index.tsx b/src/alf/index.tsx
index 06d6ebf01c..27738e91de 100644
--- a/src/alf/index.tsx
+++ b/src/alf/index.tsx
@@ -17,7 +17,7 @@ const breakpoints: {
[key: string]: number
} = {
gtMobile: 800,
- gtTablet: 1200,
+ gtTablet: 1300,
}
function getActiveBreakpoints({width}: {width: number}) {
const active: (keyof typeof breakpoints)[] = Object.keys(breakpoints).filter(
diff --git a/src/alf/themes.ts b/src/alf/themes.ts
index da96f6eff6..0c95a459ed 100644
--- a/src/alf/themes.ts
+++ b/src/alf/themes.ts
@@ -1,6 +1,7 @@
import * as tokens from '#/alf/tokens'
import type {Mutable} from '#/alf/types'
import {atoms} from '#/alf/atoms'
+import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
export type ThemeName = 'light' | 'dim' | 'dark'
export type ReadonlyTheme = typeof light
@@ -73,19 +74,19 @@ export const darkPalette: Palette = {
white: tokens.color.gray_0,
black: tokens.color.trueBlack,
- contrast_25: `hsl(211, 28%, 8%)`,
- contrast_50: `hsl(211, 28%, 11%)`,
- contrast_100: `hsl(211, 28%, 16%)`,
- contrast_200: `hsl(211, 28%, 24%)`,
- contrast_300: `hsl(211, 24%, 31%)`,
- contrast_400: `hsl(211, 24%, 38%)`,
- contrast_500: `hsl(211, 20%, 44%)`,
- contrast_600: `hsl(211, 20%, 55%)`,
- contrast_700: `hsl(211, 20%, 63%)`,
- contrast_800: `hsl(211, 20%, 71%)`,
- contrast_900: `hsl(211, 20%, 79%)`,
- contrast_950: `hsl(211, 20%, 87%)`,
- contrast_975: `hsl(211, 20%, 95%)`,
+ contrast_25: tokens.color.gray_1000,
+ contrast_50: tokens.color.gray_975,
+ contrast_100: tokens.color.gray_950,
+ contrast_200: tokens.color.gray_900,
+ contrast_300: tokens.color.gray_800,
+ contrast_400: tokens.color.gray_700,
+ contrast_500: tokens.color.gray_600,
+ contrast_600: tokens.color.gray_500,
+ contrast_700: tokens.color.gray_400,
+ contrast_800: tokens.color.gray_300,
+ contrast_900: tokens.color.gray_200,
+ contrast_950: tokens.color.gray_100,
+ contrast_975: tokens.color.gray_50,
primary_25: tokens.color.blue_25,
primary_50: tokens.color.blue_50,
@@ -132,28 +133,63 @@ export const darkPalette: Palette = {
export const dimPalette: Palette = {
...darkPalette,
- black: `hsl(211, 28%, 12%)`,
+ black: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[0]}%)`,
- contrast_25: `hsl(211, 28%, 15%)`,
- contrast_50: `hsl(211, 28%, 18%)`,
- contrast_100: `hsl(211, 28%, 24%)`,
- contrast_200: `hsl(211, 28%, 27%)`,
- contrast_300: `hsl(211, 24%, 34%)`,
- contrast_400: `hsl(211, 24%, 41%)`,
- contrast_500: `hsl(211, 20%, 52%)`,
- contrast_600: `hsl(211, 20%, 55%)`,
- contrast_700: `hsl(211, 20%, 67%)`,
- contrast_800: `hsl(211, 20%, 71%)`,
- contrast_900: `hsl(211, 20%, 79%)`,
- contrast_950: `hsl(211, 20%, 87%)`,
- contrast_975: `hsl(211, 20%, 95%)`,
+ contrast_25: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[1]}%)`,
+ contrast_50: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[2]}%)`,
+ contrast_100: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[3]}%)`,
+ contrast_200: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[4]}%)`,
+ contrast_300: `hsl(${BLUE_HUE}, 24%, ${tokens.dimScale[5]}%)`,
+ contrast_400: `hsl(${BLUE_HUE}, 24%, ${tokens.dimScale[6]}%)`,
+ contrast_500: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[7]}%)`,
+ contrast_600: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[8]}%)`,
+ contrast_700: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[9]}%)`,
+ contrast_800: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[10]}%)`,
+ contrast_900: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[11]}%)`,
+ contrast_950: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[12]}%)`,
+ contrast_975: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[13]}%)`,
- primary_600: `hsl(211, 95%, 39%)`,
- primary_700: `hsl(211, 90%, 30%)`,
- primary_800: `hsl(211, 90%, 23%)`,
- primary_900: `hsl(211, 80%, 16%)`,
- primary_950: `hsl(211, 80%, 13%)`,
- primary_975: `hsl(211, 80%, 10%)`,
+ primary_25: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[13]}%)`,
+ primary_50: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[12]}%)`,
+ primary_100: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[11]}%)`,
+ primary_200: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[10]}%)`,
+ primary_300: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[9]}%)`,
+ primary_400: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[8]}%)`,
+ primary_500: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[7]}%)`,
+ primary_600: `hsl(${BLUE_HUE}, 95%, ${tokens.dimScale[6]}%)`,
+ primary_700: `hsl(${BLUE_HUE}, 90%, ${tokens.dimScale[5]}%)`,
+ primary_800: `hsl(${BLUE_HUE}, 82%, ${tokens.dimScale[4]}%)`,
+ primary_900: `hsl(${BLUE_HUE}, 70%, ${tokens.dimScale[3]}%)`,
+ primary_950: `hsl(${BLUE_HUE}, 60%, ${tokens.dimScale[2]}%)`,
+ primary_975: `hsl(${BLUE_HUE}, 50%, ${tokens.dimScale[1]}%)`,
+
+ positive_25: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[13]}%)`,
+ positive_50: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[12]}%)`,
+ positive_100: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[11]}%)`,
+ positive_200: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[10]}%)`,
+ positive_300: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[9]}%)`,
+ positive_400: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[8]}%)`,
+ positive_500: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[7]}%)`,
+ positive_600: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[6]}%)`,
+ positive_700: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[5]}%)`,
+ positive_800: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[4]}%)`,
+ positive_900: `hsl(${GREEN_HUE}, 70%, ${tokens.dimScale[3]}%)`,
+ positive_950: `hsl(${GREEN_HUE}, 60%, ${tokens.dimScale[2]}%)`,
+ positive_975: `hsl(${GREEN_HUE}, 50%, ${tokens.dimScale[1]}%)`,
+
+ negative_25: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[13]}%)`,
+ negative_50: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[12]}%)`,
+ negative_100: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[11]}%)`,
+ negative_200: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[10]}%)`,
+ negative_300: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[9]}%)`,
+ negative_400: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[8]}%)`,
+ negative_500: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[7]}%)`,
+ negative_600: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[6]}%)`,
+ negative_700: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[5]}%)`,
+ negative_800: `hsl(${RED_HUE}, 88%, ${tokens.dimScale[4]}%)`,
+ negative_900: `hsl(${RED_HUE}, 84%, ${tokens.dimScale[3]}%)`,
+ negative_950: `hsl(${RED_HUE}, 80%, ${tokens.dimScale[2]}%)`,
+ negative_975: `hsl(${RED_HUE}, 70%, ${tokens.dimScale[1]}%)`,
} as const
export const light = {
@@ -404,17 +440,17 @@ export const dim: Theme = {
shadow_sm: {
...atoms.shadow_sm,
shadowOpacity: 0.7,
- shadowColor: `hsl(211, 28%, 3%)`,
+ shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`,
},
shadow_md: {
...atoms.shadow_md,
shadowOpacity: 0.7,
- shadowColor: `hsl(211, 28%, 3%)`,
+ shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`,
},
shadow_lg: {
...atoms.shadow_lg,
shadowOpacity: 0.7,
- shadowColor: `hsl(211, 28%, 3%)`,
+ shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`,
},
},
}
diff --git a/src/alf/tokens.ts b/src/alf/tokens.ts
index f0b8c7c692..b1468f461d 100644
--- a/src/alf/tokens.ts
+++ b/src/alf/tokens.ts
@@ -1,25 +1,32 @@
-const BLUE_HUE = 211
-const RED_HUE = 346
-const GREEN_HUE = 152
+import {
+ BLUE_HUE,
+ RED_HUE,
+ GREEN_HUE,
+ generateScale,
+} from '#/alf/util/colorGeneration'
+
+export const scale = generateScale(6, 100)
+// dim shifted 6% lighter
+export const dimScale = generateScale(12, 100)
export const color = {
trueBlack: '#000000',
- gray_0: `hsl(${BLUE_HUE}, 20%, 100%)`,
- gray_25: `hsl(${BLUE_HUE}, 20%, 97%)`,
- gray_50: `hsl(${BLUE_HUE}, 20%, 95%)`,
- gray_100: `hsl(${BLUE_HUE}, 20%, 90%)`,
- gray_200: `hsl(${BLUE_HUE}, 20%, 80%)`,
- gray_300: `hsl(${BLUE_HUE}, 20%, 70%)`,
- gray_400: `hsl(${BLUE_HUE}, 20%, 60%)`,
- gray_500: `hsl(${BLUE_HUE}, 20%, 50%)`,
- gray_600: `hsl(${BLUE_HUE}, 24%, 42%)`,
- gray_700: `hsl(${BLUE_HUE}, 24%, 34%)`,
- gray_800: `hsl(${BLUE_HUE}, 28%, 26%)`,
- gray_900: `hsl(${BLUE_HUE}, 28%, 18%)`,
- gray_950: `hsl(${BLUE_HUE}, 28%, 10%)`,
- gray_975: `hsl(${BLUE_HUE}, 28%, 7%)`,
- gray_1000: `hsl(${BLUE_HUE}, 28%, 4%)`,
+ gray_0: `hsl(${BLUE_HUE}, 20%, ${scale[14]}%)`,
+ gray_25: `hsl(${BLUE_HUE}, 20%, ${scale[13]}%)`,
+ gray_50: `hsl(${BLUE_HUE}, 20%, ${scale[12]}%)`,
+ gray_100: `hsl(${BLUE_HUE}, 20%, ${scale[11]}%)`,
+ gray_200: `hsl(${BLUE_HUE}, 20%, ${scale[10]}%)`,
+ gray_300: `hsl(${BLUE_HUE}, 20%, ${scale[9]}%)`,
+ gray_400: `hsl(${BLUE_HUE}, 20%, ${scale[8]}%)`,
+ gray_500: `hsl(${BLUE_HUE}, 20%, ${scale[7]}%)`,
+ gray_600: `hsl(${BLUE_HUE}, 24%, ${scale[6]}%)`,
+ gray_700: `hsl(${BLUE_HUE}, 24%, ${scale[5]}%)`,
+ gray_800: `hsl(${BLUE_HUE}, 28%, ${scale[4]}%)`,
+ gray_900: `hsl(${BLUE_HUE}, 28%, ${scale[3]}%)`,
+ gray_950: `hsl(${BLUE_HUE}, 28%, ${scale[2]}%)`,
+ gray_975: `hsl(${BLUE_HUE}, 28%, ${scale[1]}%)`,
+ gray_1000: `hsl(${BLUE_HUE}, 28%, ${scale[0]}%)`,
blue_25: `hsl(${BLUE_HUE}, 99%, 97%)`,
blue_50: `hsl(${BLUE_HUE}, 99%, 95%)`,
diff --git a/src/alf/util/colorGeneration.ts b/src/alf/util/colorGeneration.ts
new file mode 100644
index 0000000000..929a01d3a7
--- /dev/null
+++ b/src/alf/util/colorGeneration.ts
@@ -0,0 +1,17 @@
+export const BLUE_HUE = 211
+export const RED_HUE = 346
+export const GREEN_HUE = 152
+
+/**
+ * Smooth progression of lightness "stops" for generating HSL colors.
+ */
+export const COLOR_STOPS = [
+ 0, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.85, 0.9, 0.95, 1,
+]
+
+export function generateScale(start: number, end: number) {
+ const range = end - start
+ return COLOR_STOPS.map(stop => {
+ return start + range * stop
+ })
+}
diff --git a/src/alf/util/platform.ts b/src/alf/util/platform.ts
index 544f5480b6..294e08a8b0 100644
--- a/src/alf/util/platform.ts
+++ b/src/alf/util/platform.ts
@@ -1,25 +1,25 @@
-import {Platform} from 'react-native'
+import {isAndroid, isIOS, isNative, isWeb} from 'platform/detection'
export function web(value: any) {
- return Platform.select({
- web: value,
- })
+ if (isWeb) {
+ return value
+ }
}
export function ios(value: any) {
- return Platform.select({
- ios: value,
- })
+ if (isIOS) {
+ return value
+ }
}
export function android(value: any) {
- return Platform.select({
- android: value,
- })
+ if (isAndroid) {
+ return value
+ }
}
export function native(value: any) {
- return Platform.select({
- native: value,
- })
+ if (isNative) {
+ return value
+ }
}
diff --git a/src/components/Button.tsx b/src/components/Button.tsx
index 4addd28a3b..2d65b56834 100644
--- a/src/components/Button.tsx
+++ b/src/components/Button.tsx
@@ -165,7 +165,7 @@ export function Button({
if (!disabled) {
baseStyles.push(a.border, {
- borderColor: tokens.color.blue_500,
+ borderColor: t.palette.primary_500,
})
hoverStyles.push(a.border, {
backgroundColor: light
@@ -174,7 +174,7 @@ export function Button({
})
} else {
baseStyles.push(a.border, {
- borderColor: light ? tokens.color.blue_200 : tokens.color.blue_900,
+ borderColor: light ? t.palette.primary_200 : t.palette.primary_900,
})
}
} else if (variant === 'ghost') {
@@ -191,20 +191,14 @@ export function Button({
if (variant === 'solid') {
if (!disabled) {
baseStyles.push({
- backgroundColor: light
- ? tokens.color.gray_50
- : tokens.color.gray_900,
+ backgroundColor: t.palette.contrast_50,
})
hoverStyles.push({
- backgroundColor: light
- ? tokens.color.gray_100
- : tokens.color.gray_950,
+ backgroundColor: t.palette.contrast_100,
})
} else {
baseStyles.push({
- backgroundColor: light
- ? tokens.color.gray_200
- : tokens.color.gray_950,
+ backgroundColor: t.palette.contrast_200,
})
}
} else if (variant === 'outline') {
@@ -214,21 +208,19 @@ export function Button({
if (!disabled) {
baseStyles.push(a.border, {
- borderColor: light ? tokens.color.gray_300 : tokens.color.gray_700,
+ borderColor: t.palette.contrast_300,
})
- hoverStyles.push(a.border, t.atoms.bg_contrast_50)
+ hoverStyles.push(t.atoms.bg_contrast_50)
} else {
baseStyles.push(a.border, {
- borderColor: light ? tokens.color.gray_200 : tokens.color.gray_800,
+ borderColor: t.palette.contrast_200,
})
}
} else if (variant === 'ghost') {
if (!disabled) {
baseStyles.push(t.atoms.bg)
hoverStyles.push({
- backgroundColor: light
- ? tokens.color.gray_100
- : tokens.color.gray_900,
+ backgroundColor: t.palette.contrast_100,
})
}
}
@@ -236,14 +228,14 @@ export function Button({
if (variant === 'solid') {
if (!disabled) {
baseStyles.push({
- backgroundColor: t.palette.negative_400,
+ backgroundColor: t.palette.negative_500,
})
hoverStyles.push({
- backgroundColor: t.palette.negative_500,
+ backgroundColor: t.palette.negative_600,
})
} else {
baseStyles.push({
- backgroundColor: t.palette.negative_600,
+ backgroundColor: t.palette.negative_700,
})
}
} else if (variant === 'outline') {
@@ -253,7 +245,7 @@ export function Button({
if (!disabled) {
baseStyles.push(a.border, {
- borderColor: t.palette.negative_400,
+ borderColor: t.palette.negative_500,
})
hoverStyles.push(a.border, {
backgroundColor: light
@@ -273,7 +265,7 @@ export function Button({
hoverStyles.push({
backgroundColor: light
? t.palette.negative_100
- : t.palette.negative_950,
+ : t.palette.negative_975,
})
}
}
@@ -460,31 +452,31 @@ export function useSharedButtonTextStyles() {
if (variant === 'solid' || variant === 'gradient') {
if (!disabled) {
baseStyles.push({
- color: light ? tokens.color.gray_700 : tokens.color.gray_100,
+ color: t.palette.contrast_700,
})
} else {
baseStyles.push({
- color: light ? tokens.color.gray_400 : tokens.color.gray_700,
+ color: t.palette.contrast_400,
})
}
} else if (variant === 'outline') {
if (!disabled) {
baseStyles.push({
- color: light ? tokens.color.gray_600 : tokens.color.gray_300,
+ color: t.palette.contrast_600,
})
} else {
baseStyles.push({
- color: light ? tokens.color.gray_400 : tokens.color.gray_700,
+ color: t.palette.contrast_300,
})
}
} else if (variant === 'ghost') {
if (!disabled) {
baseStyles.push({
- color: light ? tokens.color.gray_600 : tokens.color.gray_300,
+ color: t.palette.contrast_600,
})
} else {
baseStyles.push({
- color: light ? tokens.color.gray_400 : tokens.color.gray_600,
+ color: t.palette.contrast_300,
})
}
}
diff --git a/src/components/Dialog/context.ts b/src/components/Dialog/context.ts
index f0c7c983a9..9b571e8e9c 100644
--- a/src/components/Dialog/context.ts
+++ b/src/components/Dialog/context.ts
@@ -3,7 +3,7 @@ import React from 'react'
import {useDialogStateContext} from '#/state/dialogs'
import {
DialogContextProps,
- DialogControlProps,
+ DialogControlRefProps,
DialogOuterProps,
} from '#/components/Dialog/types'
@@ -17,11 +17,12 @@ export function useDialogContext() {
export function useDialogControl(): DialogOuterProps['control'] {
const id = React.useId()
- const control = React.useRef({
+ const control = React.useRef({
open: () => {},
close: () => {},
})
- const {activeDialogs} = useDialogStateContext()
+ const {activeDialogs, openDialogs} = useDialogStateContext()
+ const isOpen = openDialogs.includes(id)
React.useEffect(() => {
activeDialogs.current.set(id, control)
@@ -31,9 +32,18 @@ export function useDialogControl(): DialogOuterProps['control'] {
}
}, [id, activeDialogs])
- return {
- ref: control,
- open: () => control.current.open(),
- close: cb => control.current.close(cb),
- }
+ return React.useMemo(
+ () => ({
+ id,
+ ref: control,
+ isOpen,
+ open: () => {
+ control.current.open()
+ },
+ close: cb => {
+ control.current.close(cb)
+ },
+ }),
+ [id, control, isOpen],
+ )
}
diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx
index 97c3340d3f..5d926f59f4 100644
--- a/src/components/Dialog/index.tsx
+++ b/src/components/Dialog/index.tsx
@@ -1,17 +1,22 @@
import React, {useImperativeHandle} from 'react'
-import {View, Dimensions} from 'react-native'
+import {View, Dimensions, Keyboard, Pressable} from 'react-native'
import BottomSheet, {
- BottomSheetBackdrop,
BottomSheetFlatList,
+ BottomSheetBackdropProps,
BottomSheetScrollView,
BottomSheetTextInput,
BottomSheetView,
+ useBottomSheet,
+ WINDOW_HEIGHT,
} from '@gorhom/bottom-sheet'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
+import Animated, {useAnimatedStyle} from 'react-native-reanimated'
import {useTheme, atoms as a, flatten} from '#/alf'
import {Portal} from '#/components/Portal'
import {createInput} from '#/components/forms/TextField'
+import {logger} from '#/logger'
+import {useDialogStateControlContext} from '#/state/dialogs'
import {
DialogOuterProps,
@@ -26,6 +31,47 @@ export * from '#/components/Dialog/types'
export const Input = createInput(BottomSheetTextInput)
export const FlatList = BottomSheetFlatList
+function Backdrop(props: BottomSheetBackdropProps) {
+ const t = useTheme()
+ const bottomSheet = useBottomSheet()
+
+ const animatedStyle = useAnimatedStyle(() => {
+ const opacity =
+ (Math.abs(WINDOW_HEIGHT - props.animatedPosition.value) - 50) / 1000
+
+ return {
+ opacity: Math.min(Math.max(opacity, 0), 0.55),
+ }
+ })
+
+ const onPress = React.useCallback(() => {
+ bottomSheet.close()
+ }, [bottomSheet])
+
+ return (
+
+
+
+ )
+}
+
export function Outer({
children,
control,
@@ -38,6 +84,7 @@ export function Outer({
const hasSnapPoints = !!sheetOptions.snapPoints
const insets = useSafeAreaInsets()
const closeCallback = React.useRef<() => void>()
+ const {setDialogIsOpen} = useDialogStateControlContext()
/*
* Used to manage open/closed, but index is otherwise handled internally by `BottomSheet`
@@ -51,14 +98,15 @@ export function Outer({
const open = React.useCallback(
({index} = {}) => {
+ setDialogIsOpen(control.id, true)
// can be set to any index of `snapPoints`, but `0` is the first i.e. "open"
setOpenIndex(index || 0)
},
- [setOpenIndex],
+ [setOpenIndex, setDialogIsOpen, control.id],
)
const close = React.useCallback(cb => {
- if (cb) {
+ if (cb && typeof cb === 'function') {
closeCallback.current = cb
}
sheet.current?.close()
@@ -73,63 +121,66 @@ export function Outer({
[open, close],
)
- const onChange = React.useCallback(
- (index: number) => {
- if (index === -1) {
- closeCallback.current?.()
- closeCallback.current = undefined
- onClose?.()
- setOpenIndex(-1)
- }
- },
- [onClose, setOpenIndex],
- )
+ const onCloseInner = React.useCallback(() => {
+ Keyboard.dismiss()
+ try {
+ closeCallback.current?.()
+ } catch (e: any) {
+ logger.error(`Dialog closeCallback failed`, {
+ message: e.message,
+ })
+ } finally {
+ closeCallback.current = undefined
+ }
+ setDialogIsOpen(control.id, false)
+ onClose?.()
+ setOpenIndex(-1)
+ }, [control.id, onClose, setDialogIsOpen])
const context = React.useMemo(() => ({close}), [close])
return (
isOpen && (
- (
-
- )}
- handleIndicatorStyle={{backgroundColor: t.palette.primary_500}}
- handleStyle={{display: 'none'}}
- onChange={onChange}>
-
-
- {children}
-
-
+
+
+
+
+ {children}
+
+
+
)
)
@@ -179,8 +230,15 @@ export function ScrollableInner({children, style}: DialogInnerProps) {
export function Handle() {
const t = useTheme()
+
+ const onTouchStart = React.useCallback(() => {
+ Keyboard.dismiss()
+ }, [])
+
return (
-
+
{
setIsOpen(true)
- }, [setIsOpen])
+ setDialogIsOpen(control.id, true)
+ }, [setIsOpen, setDialogIsOpen, control.id])
const close = React.useCallback(async () => {
setIsVisible(false)
await new Promise(resolve => setTimeout(resolve, 150))
setIsOpen(false)
setIsVisible(true)
+ setDialogIsOpen(control.id, false)
onClose?.()
- }, [onClose, setIsOpen])
+ }, [onClose, setIsOpen, setDialogIsOpen, control.id])
useImperativeHandle(
control.ref,
@@ -189,9 +193,9 @@ export function Close() {
diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts
index 75ba825ac9..fa9398fe05 100644
--- a/src/components/Dialog/types.ts
+++ b/src/components/Dialog/types.ts
@@ -6,8 +6,27 @@ import {ViewStyleProp} from '#/alf'
type A11yProps = Required
+/**
+ * Mutated by useImperativeHandle to provide a public API for controlling the
+ * dialog. The methods here will actually become the handlers defined within
+ * the `Dialog.Outer` component.
+ */
+export type DialogControlRefProps = {
+ open: (options?: DialogControlOpenOptions) => void
+ close: (callback?: () => void) => void
+}
+
+/**
+ * The return type of the useDialogControl hook.
+ */
+export type DialogControlProps = DialogControlRefProps & {
+ id: string
+ ref: React.RefObject
+ isOpen: boolean
+}
+
export type DialogContextProps = {
- close: () => void
+ close: DialogControlProps['close']
}
export type DialogControlOpenOptions = {
@@ -20,15 +39,8 @@ export type DialogControlOpenOptions = {
index?: number
}
-export type DialogControlProps = {
- open: (options?: DialogControlOpenOptions) => void
- close: (callback?: () => void) => void
-}
-
export type DialogOuterProps = {
- control: {
- ref: React.RefObject
- } & DialogControlProps
+ control: DialogControlProps
onClose?: () => void
nativeOptions?: {
sheet?: Omit
diff --git a/src/components/Link.tsx b/src/components/Link.tsx
index 0a654fed28..8c963909be 100644
--- a/src/components/Link.tsx
+++ b/src/components/Link.tsx
@@ -49,7 +49,7 @@ type BaseLinkProps = Pick<
*
* Note: atm this only works for `InlineLink`s with a string child.
*/
- warnOnMismatchingTextChild?: boolean
+ disableMismatchWarning?: boolean
/**
* Callback for when the link is pressed. Prevent default and return `false`
@@ -69,7 +69,7 @@ export function useLink({
to,
displayText,
action = 'push',
- warnOnMismatchingTextChild,
+ disableMismatchWarning,
onPress: outerOnPress,
}: BaseLinkProps & {
displayText: string
@@ -90,7 +90,7 @@ export function useLink({
if (exitEarlyIfFalse === false) return
const requiresWarning = Boolean(
- warnOnMismatchingTextChild &&
+ !disableMismatchWarning &&
displayText &&
isExternal &&
linkRequiresWarning(href, displayText),
@@ -148,7 +148,7 @@ export function useLink({
},
[
outerOnPress,
- warnOnMismatchingTextChild,
+ disableMismatchWarning,
displayText,
isExternal,
href,
@@ -167,7 +167,7 @@ export function useLink({
}
}
-export type LinkProps = Omit &
+export type LinkProps = Omit &
Omit
/**
@@ -226,7 +226,7 @@ export function InlineLink({
children,
to,
action = 'push',
- warnOnMismatchingTextChild,
+ disableMismatchWarning,
style,
onPress: outerOnPress,
download,
@@ -239,7 +239,7 @@ export function InlineLink({
to,
displayText: stringChildren ? children : '',
action,
- warnOnMismatchingTextChild,
+ disableMismatchWarning,
onPress: outerOnPress,
})
const {
diff --git a/src/components/Lists.tsx b/src/components/Lists.tsx
new file mode 100644
index 0000000000..58aa74b388
--- /dev/null
+++ b/src/components/Lists.tsx
@@ -0,0 +1,249 @@
+import React from 'react'
+import {atoms as a, useBreakpoints, useTheme} from '#/alf'
+import {View} from 'react-native'
+import {CenteredView} from 'view/com/util/Views'
+import {Loader} from '#/components/Loader'
+import {Trans} from '@lingui/macro'
+import {cleanError} from 'lib/strings/errors'
+import {Button} from '#/components/Button'
+import {Text} from '#/components/Typography'
+import {StackActions} from '@react-navigation/native'
+import {useNavigation} from '@react-navigation/core'
+import {NavigationProp} from 'lib/routes/types'
+import {router} from '#/routes'
+
+export function ListFooter({
+ isFetching,
+ isError,
+ error,
+ onRetry,
+}: {
+ isFetching: boolean
+ isError: boolean
+ error?: string
+ onRetry?: () => Promise
+}) {
+ const t = useTheme()
+
+ return (
+
+ {isFetching ? (
+
+ ) : (
+
+ )}
+
+ )
+}
+
+function ListFooterMaybeError({
+ isError,
+ error,
+ onRetry,
+}: {
+ isError: boolean
+ error?: string
+ onRetry?: () => Promise
+}) {
+ const t = useTheme()
+
+ if (!isError) return null
+
+ return (
+
+
+
+ {error ? (
+ cleanError(error)
+ ) : (
+ Oops, something went wrong!
+ )}
+
+
+
+
+ )
+}
+
+export function ListHeaderDesktop({
+ title,
+ subtitle,
+}: {
+ title: string
+ subtitle?: string
+}) {
+ const {gtTablet} = useBreakpoints()
+ const t = useTheme()
+
+ if (!gtTablet) return null
+
+ return (
+
+ {title}
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : undefined}
+
+ )
+}
+
+export function ListMaybePlaceholder({
+ isLoading,
+ isEmpty,
+ isError,
+ empty,
+ error,
+ notFoundType = 'page',
+ onRetry,
+}: {
+ isLoading: boolean
+ isEmpty: boolean
+ isError: boolean
+ empty?: string
+ error?: string
+ notFoundType?: 'page' | 'results'
+ onRetry?: () => Promise
+}) {
+ const navigation = useNavigation()
+ const t = useTheme()
+ const {gtMobile, gtTablet} = useBreakpoints()
+
+ const canGoBack = navigation.canGoBack()
+ const onGoBack = React.useCallback(() => {
+ if (canGoBack) {
+ navigation.goBack()
+ } else {
+ navigation.navigate('HomeTab')
+
+ // Checking the state for routes ensures that web doesn't encounter errors while going back
+ if (navigation.getState()?.routes) {
+ navigation.dispatch(StackActions.push(...router.matchPath('/')))
+ } else {
+ navigation.navigate('HomeTab')
+ navigation.dispatch(StackActions.popToTop())
+ }
+ }
+ }, [navigation, canGoBack])
+
+ if (!isEmpty) return null
+
+ return (
+
+ {isLoading ? (
+
+
+
+ ) : (
+ <>
+
+
+ {isError ? (
+ Oops!
+ ) : isEmpty ? (
+ <>
+ {notFoundType === 'results' ? (
+ No results found
+ ) : (
+ Page not found
+ )}
+ >
+ ) : undefined}
+
+
+ {isError ? (
+
+ {error ? error : Something went wrong!}
+
+ ) : isEmpty ? (
+
+ {empty ? (
+ empty
+ ) : (
+
+ We're sorry! We can't find the page you were looking for.
+
+ )}
+
+ ) : undefined}
+
+
+ {isError && onRetry && (
+
+ )}
+
+
+ >
+ )}
+
+ )
+}
diff --git a/src/components/Menu/context.tsx b/src/components/Menu/context.tsx
new file mode 100644
index 0000000000..9fc91f6815
--- /dev/null
+++ b/src/components/Menu/context.tsx
@@ -0,0 +1,8 @@
+import React from 'react'
+
+import type {ContextType} from '#/components/Menu/types'
+
+export const Context = React.createContext({
+ // @ts-ignore
+ control: null,
+})
diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx
new file mode 100644
index 0000000000..ee96a5667e
--- /dev/null
+++ b/src/components/Menu/index.tsx
@@ -0,0 +1,190 @@
+import React from 'react'
+import {View, Pressable} from 'react-native'
+import flattenReactChildren from 'react-keyed-flatten-children'
+
+import {atoms as a, useTheme} from '#/alf'
+import * as Dialog from '#/components/Dialog'
+import {useInteractionState} from '#/components/hooks/useInteractionState'
+import {Text} from '#/components/Typography'
+
+import {Context} from '#/components/Menu/context'
+import {
+ ContextType,
+ TriggerProps,
+ ItemProps,
+ GroupProps,
+ ItemTextProps,
+ ItemIconProps,
+} from '#/components/Menu/types'
+
+export {useDialogControl as useMenuControl} from '#/components/Dialog'
+
+export function useMemoControlContext() {
+ return React.useContext(Context)
+}
+
+export function Root({
+ children,
+ control,
+}: React.PropsWithChildren<{
+ control?: Dialog.DialogOuterProps['control']
+}>) {
+ const defaultControl = Dialog.useDialogControl()
+ const context = React.useMemo(
+ () => ({
+ control: control || defaultControl,
+ }),
+ [control, defaultControl],
+ )
+
+ return {children}
+}
+
+export function Trigger({children, label}: TriggerProps) {
+ const {control} = React.useContext(Context)
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+ const {
+ state: pressed,
+ onIn: onPressIn,
+ onOut: onPressOut,
+ } = useInteractionState()
+
+ return children({
+ isNative: true,
+ control,
+ state: {
+ hovered: false,
+ focused,
+ pressed,
+ },
+ props: {
+ onPress: control.open,
+ onFocus,
+ onBlur,
+ onPressIn,
+ onPressOut,
+ accessibilityLabel: label,
+ },
+ })
+}
+
+export function Outer({children}: React.PropsWithChildren<{}>) {
+ const context = React.useContext(Context)
+
+ return (
+
+
+
+ {/* Re-wrap with context since Dialogs are portal-ed to root */}
+
+
+ {children}
+
+
+
+
+ )
+}
+
+export function Item({children, label, style, onPress, ...rest}: ItemProps) {
+ const t = useTheme()
+ const {control} = React.useContext(Context)
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+ const {
+ state: pressed,
+ onIn: onPressIn,
+ onOut: onPressOut,
+ } = useInteractionState()
+
+ return (
+ {
+ onPress(e)
+
+ if (!e.defaultPrevented) {
+ control?.close()
+ }
+ }}
+ onFocus={onFocus}
+ onBlur={onBlur}
+ onPressIn={onPressIn}
+ onPressOut={onPressOut}
+ style={[
+ a.flex_row,
+ a.align_center,
+ a.gap_sm,
+ a.px_md,
+ a.rounded_md,
+ a.border,
+ t.atoms.bg_contrast_25,
+ t.atoms.border_contrast_low,
+ {minHeight: 44, paddingVertical: 10},
+ style,
+ (focused || pressed) && [t.atoms.bg_contrast_50],
+ ]}>
+ {children}
+
+ )
+}
+
+export function ItemText({children, style}: ItemTextProps) {
+ const t = useTheme()
+ return (
+
+ {children}
+
+ )
+}
+
+export function ItemIcon({icon: Comp}: ItemIconProps) {
+ const t = useTheme()
+ return
+}
+
+export function Group({children, style}: GroupProps) {
+ const t = useTheme()
+ return (
+
+ {flattenReactChildren(children).map((child, i) => {
+ return React.isValidElement(child) && child.type === Item ? (
+
+ {i > 0 ? (
+
+ ) : null}
+ {React.cloneElement(child, {
+ // @ts-ignore
+ style: {
+ borderRadius: 0,
+ borderWidth: 0,
+ },
+ })}
+
+ ) : null
+ })}
+
+ )
+}
+
+export function Divider() {
+ return null
+}
diff --git a/src/components/Menu/index.web.tsx b/src/components/Menu/index.web.tsx
new file mode 100644
index 0000000000..ca2e40566d
--- /dev/null
+++ b/src/components/Menu/index.web.tsx
@@ -0,0 +1,247 @@
+import React from 'react'
+import {View, Pressable} from 'react-native'
+import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
+
+import * as Dialog from '#/components/Dialog'
+import {useInteractionState} from '#/components/hooks/useInteractionState'
+import {atoms as a, useTheme, flatten, web} from '#/alf'
+import {Text} from '#/components/Typography'
+
+import {
+ ContextType,
+ TriggerProps,
+ ItemProps,
+ GroupProps,
+ ItemTextProps,
+ ItemIconProps,
+} from '#/components/Menu/types'
+import {Context} from '#/components/Menu/context'
+
+export function useMenuControl(): Dialog.DialogControlProps {
+ const id = React.useId()
+ const [isOpen, setIsOpen] = React.useState(false)
+
+ return React.useMemo(
+ () => ({
+ id,
+ ref: {current: null},
+ isOpen,
+ open() {
+ setIsOpen(true)
+ },
+ close() {
+ setIsOpen(false)
+ },
+ }),
+ [id, isOpen, setIsOpen],
+ )
+}
+
+export function useMemoControlContext() {
+ return React.useContext(Context)
+}
+
+export function Root({
+ children,
+ control,
+}: React.PropsWithChildren<{
+ control?: Dialog.DialogOuterProps['control']
+}>) {
+ const defaultControl = useMenuControl()
+ const context = React.useMemo(
+ () => ({
+ control: control || defaultControl,
+ }),
+ [control, defaultControl],
+ )
+ const onOpenChange = React.useCallback(
+ (open: boolean) => {
+ if (context.control.isOpen && !open) {
+ context.control.close()
+ } else if (!context.control.isOpen && open) {
+ context.control.open()
+ }
+ },
+ [context.control],
+ )
+
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export function Trigger({children, label, style}: TriggerProps) {
+ const {control} = React.useContext(Context)
+ const {
+ state: hovered,
+ onIn: onMouseEnter,
+ onOut: onMouseLeave,
+ } = useInteractionState()
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+
+ return (
+
+ {
+ control.open()
+ }}
+ {...web({
+ onMouseEnter,
+ onMouseLeave,
+ })}>
+ {children({
+ isNative: false,
+ control,
+ state: {
+ hovered,
+ focused,
+ pressed: false,
+ },
+ props: {},
+ })}
+
+
+ )
+}
+
+export function Outer({children}: React.PropsWithChildren<{}>) {
+ const t = useTheme()
+
+ return (
+
+
+
+ {children}
+
+
+
+
+
+ )
+}
+
+export function Item({children, label, onPress, ...rest}: ItemProps) {
+ const t = useTheme()
+ const {control} = React.useContext(Context)
+ const {
+ state: hovered,
+ onIn: onMouseEnter,
+ onOut: onMouseLeave,
+ } = useInteractionState()
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+
+ return (
+
+ {
+ onPress(e)
+
+ /**
+ * Ported forward from Radix
+ * @see https://www.radix-ui.com/primitives/docs/components/dropdown-menu#item
+ */
+ if (!e.defaultPrevented) {
+ control.close()
+ }
+ }}
+ onFocus={onFocus}
+ onBlur={onBlur}
+ // need `flatten` here for Radix compat
+ style={flatten([
+ a.flex_row,
+ a.align_center,
+ a.gap_sm,
+ a.py_sm,
+ a.rounded_xs,
+ {minHeight: 32, paddingHorizontal: 10},
+ web({outline: 0}),
+ (hovered || focused) && [
+ web({outline: '0 !important'}),
+ t.name === 'light'
+ ? t.atoms.bg_contrast_25
+ : t.atoms.bg_contrast_50,
+ ],
+ ])}
+ {...web({
+ onMouseEnter,
+ onMouseLeave,
+ })}>
+ {children}
+
+
+ )
+}
+
+export function ItemText({children, style}: ItemTextProps) {
+ const t = useTheme()
+ return (
+
+ {children}
+
+ )
+}
+
+export function ItemIcon({icon: Comp, position = 'left'}: ItemIconProps) {
+ const t = useTheme()
+ return (
+
+ )
+}
+
+export function Group({children}: GroupProps) {
+ return children
+}
+
+export function Divider() {
+ const t = useTheme()
+ return (
+
+ )
+}
diff --git a/src/components/Menu/types.ts b/src/components/Menu/types.ts
new file mode 100644
index 0000000000..2f52e63906
--- /dev/null
+++ b/src/components/Menu/types.ts
@@ -0,0 +1,72 @@
+import React from 'react'
+import {GestureResponderEvent, PressableProps} from 'react-native'
+
+import {Props as SVGIconProps} from '#/components/icons/common'
+import * as Dialog from '#/components/Dialog'
+import {TextStyleProp, ViewStyleProp} from '#/alf'
+
+export type ContextType = {
+ control: Dialog.DialogOuterProps['control']
+}
+
+export type TriggerProps = ViewStyleProp & {
+ children(props: TriggerChildProps): React.ReactNode
+ label: string
+}
+export type TriggerChildProps =
+ | {
+ isNative: true
+ control: Dialog.DialogOuterProps['control']
+ state: {
+ /**
+ * Web only, `false` on native
+ */
+ hovered: false
+ focused: boolean
+ pressed: boolean
+ }
+ /**
+ * We don't necessarily know what these will be spread on to, so we
+ * should add props one-by-one.
+ *
+ * On web, these properties are applied to a parent `Pressable`, so this
+ * object is empty.
+ */
+ props: {
+ onPress: () => void
+ onFocus: () => void
+ onBlur: () => void
+ onPressIn: () => void
+ onPressOut: () => void
+ accessibilityLabel: string
+ }
+ }
+ | {
+ isNative: false
+ control: Dialog.DialogOuterProps['control']
+ state: {
+ hovered: boolean
+ focused: boolean
+ /**
+ * Native only, `false` on web
+ */
+ pressed: false
+ }
+ props: {}
+ }
+
+export type ItemProps = React.PropsWithChildren<
+ Omit &
+ ViewStyleProp & {
+ label: string
+ onPress: (e: GestureResponderEvent) => void
+ }
+>
+
+export type ItemTextProps = React.PropsWithChildren
+export type ItemIconProps = React.PropsWithChildren<{
+ icon: React.ComponentType
+ position?: 'left' | 'right'
+}>
+
+export type GroupProps = React.PropsWithChildren
diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx
index 411679102b..8e55bd8347 100644
--- a/src/components/Prompt.tsx
+++ b/src/components/Prompt.tsx
@@ -89,7 +89,7 @@ export function Cancel({
color="secondary"
size="small"
label={_(msg`Cancel`)}
- onPress={close}>
+ onPress={() => close()}>
{children}
)
diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx
index c72fcabdd8..1a14415cf8 100644
--- a/src/components/RichText.tsx
+++ b/src/components/RichText.tsx
@@ -1,11 +1,15 @@
import React from 'react'
import {RichText as RichTextAPI, AppBskyRichtextFacet} from '@atproto/api'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
-import {atoms as a, TextStyleProp, flatten} from '#/alf'
+import {atoms as a, TextStyleProp, flatten, useTheme, web, native} from '#/alf'
import {InlineLink} from '#/components/Link'
import {Text, TextProps} from '#/components/Typography'
import {toShortUrl} from 'lib/strings/url-helpers'
-import {getAgent} from '#/state/session'
+import {TagMenu, useTagMenuControl} from '#/components/TagMenu'
+import {isNative} from '#/platform/detection'
+import {useInteractionState} from '#/components/hooks/useInteractionState'
const WORD_WRAP = {wordWrap: 1}
@@ -15,37 +19,25 @@ export function RichText({
style,
numberOfLines,
disableLinks,
- resolveFacets = false,
selectable,
+ enableTags = false,
+ authorHandle,
}: TextStyleProp &
Pick & {
value: RichTextAPI | string
testID?: string
numberOfLines?: number
disableLinks?: boolean
- resolveFacets?: boolean
+ enableTags?: boolean
+ authorHandle?: string
}) {
- const detected = React.useRef(false)
- const [richText, setRichText] = React.useState(() =>
- value instanceof RichTextAPI ? value : new RichTextAPI({text: value}),
+ const richText = React.useMemo(
+ () =>
+ value instanceof RichTextAPI ? value : new RichTextAPI({text: value}),
+ [value],
)
const styles = [a.leading_snug, flatten(style)]
- React.useEffect(() => {
- if (!resolveFacets) return
-
- async function detectFacets() {
- const rt = new RichTextAPI({text: richText.text})
- await rt.detectFacets(getAgent())
- setRichText(rt)
- }
-
- if (!detected.current) {
- detected.current = true
- detectFacets()
- }
- }, [richText, setRichText, resolveFacets])
-
const {text, facets} = richText
if (!facets?.length) {
@@ -85,6 +77,7 @@ export function RichText({
for (const segment of richText.segments()) {
const link = segment.link
const mention = segment.mention
+ const tag = segment.tag
if (
mention &&
AppBskyRichtextFacet.validateMention(mention).success &&
@@ -112,12 +105,27 @@ export function RichText({
to={link.uri}
style={[...styles, {pointerEvents: 'auto'}]}
// @ts-ignore TODO
- dataSet={WORD_WRAP}
- warnOnMismatchingLabel>
+ dataSet={WORD_WRAP}>
{toShortUrl(segment.text)}
,
)
}
+ } else if (
+ !disableLinks &&
+ enableTags &&
+ tag &&
+ AppBskyRichtextFacet.validateTag(tag).success
+ ) {
+ els.push(
+ ,
+ )
} else {
els.push(segment.text)
}
@@ -136,3 +144,81 @@ export function RichText({
)
}
+
+function RichTextTag({
+ text,
+ tag,
+ style,
+ selectable,
+ authorHandle,
+}: {
+ text: string
+ tag: string
+ selectable?: boolean
+ authorHandle?: string
+} & TextStyleProp) {
+ const t = useTheme()
+ const {_} = useLingui()
+ const control = useTagMenuControl()
+ const {
+ state: hovered,
+ onIn: onHoverIn,
+ onOut: onHoverOut,
+ } = useInteractionState()
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+ const {
+ state: pressed,
+ onIn: onPressIn,
+ onOut: onPressOut,
+ } = useInteractionState()
+
+ const open = React.useCallback(() => {
+ control.open()
+ }, [control])
+
+ /*
+ * N.B. On web, this is wrapped in another pressable comopnent with a11y
+ * labels, etc. That's why only some of these props are applied here.
+ */
+
+ return (
+
+
+
+ {text}
+
+
+
+ )
+}
diff --git a/src/components/TagMenu/index.tsx b/src/components/TagMenu/index.tsx
new file mode 100644
index 0000000000..849a3f42d1
--- /dev/null
+++ b/src/components/TagMenu/index.tsx
@@ -0,0 +1,275 @@
+import React from 'react'
+import {View} from 'react-native'
+import {useNavigation} from '@react-navigation/native'
+import {useLingui} from '@lingui/react'
+import {msg, Trans} from '@lingui/macro'
+
+import {atoms as a, native, useTheme} from '#/alf'
+import * as Dialog from '#/components/Dialog'
+import {Text} from '#/components/Typography'
+import {Button, ButtonText} from '#/components/Button'
+import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2'
+import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person'
+import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute'
+import {Divider} from '#/components/Divider'
+import {Link} from '#/components/Link'
+import {makeSearchLink} from '#/lib/routes/links'
+import {NavigationProp} from '#/lib/routes/types'
+import {
+ usePreferencesQuery,
+ useUpsertMutedWordsMutation,
+ useRemoveMutedWordMutation,
+} from '#/state/queries/preferences'
+import {Loader} from '#/components/Loader'
+import {isInvalidHandle} from '#/lib/strings/handles'
+
+export function useTagMenuControl() {
+ return Dialog.useDialogControl()
+}
+
+export function TagMenu({
+ children,
+ control,
+ tag,
+ authorHandle,
+}: React.PropsWithChildren<{
+ control: Dialog.DialogOuterProps['control']
+ /**
+ * This should be the sanitized tag value from the facet itself, not the
+ * "display" value with a leading `#`.
+ */
+ tag: string
+ authorHandle?: string
+}>) {
+ const {_} = useLingui()
+ const t = useTheme()
+ const navigation = useNavigation()
+ const {isLoading: isPreferencesLoading, data: preferences} =
+ usePreferencesQuery()
+ const {
+ mutateAsync: upsertMutedWord,
+ variables: optimisticUpsert,
+ reset: resetUpsert,
+ } = useUpsertMutedWordsMutation()
+ const {
+ mutateAsync: removeMutedWord,
+ variables: optimisticRemove,
+ reset: resetRemove,
+ } = useRemoveMutedWordMutation()
+ const displayTag = '#' + tag
+
+ const isMuted = Boolean(
+ (preferences?.mutedWords?.find(
+ m => m.value === tag && m.targets.includes('tag'),
+ ) ??
+ optimisticUpsert?.find(
+ m => m.value === tag && m.targets.includes('tag'),
+ )) &&
+ !(optimisticRemove?.value === tag),
+ )
+
+ return (
+ <>
+ {children}
+
+
+
+
+
+ {isPreferencesLoading ? (
+
+
+
+ ) : (
+ <>
+
+ {
+ e.preventDefault()
+
+ control.close(() => {
+ navigation.push('Hashtag', {
+ tag: encodeURIComponent(tag),
+ })
+ })
+
+ return false
+ }}>
+
+
+
+
+ See{' '}
+
+ {displayTag}
+ {' '}
+ posts
+
+
+
+
+
+ {authorHandle && !isInvalidHandle(authorHandle) && (
+ <>
+
+
+ {
+ e.preventDefault()
+
+ control.close(() => {
+ navigation.push('Hashtag', {
+ tag: encodeURIComponent(tag),
+ author: authorHandle,
+ })
+ })
+
+ return false
+ }}>
+
+
+
+
+ See{' '}
+
+ {displayTag}
+ {' '}
+ posts by this user
+
+
+
+
+ >
+ )}
+
+ {preferences ? (
+ <>
+
+
+
+ >
+ ) : null}
+
+
+
+ >
+ )}
+
+
+ >
+ )
+}
diff --git a/src/components/TagMenu/index.web.tsx b/src/components/TagMenu/index.web.tsx
new file mode 100644
index 0000000000..8245bd0191
--- /dev/null
+++ b/src/components/TagMenu/index.web.tsx
@@ -0,0 +1,149 @@
+import React from 'react'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {useNavigation} from '@react-navigation/native'
+
+import {isInvalidHandle} from '#/lib/strings/handles'
+import {EventStopper} from '#/view/com/util/EventStopper'
+import {NativeDropdown} from '#/view/com/util/forms/NativeDropdown'
+import {NavigationProp} from '#/lib/routes/types'
+import {
+ usePreferencesQuery,
+ useUpsertMutedWordsMutation,
+ useRemoveMutedWordMutation,
+} from '#/state/queries/preferences'
+import {enforceLen} from '#/lib/strings/helpers'
+import {web} from '#/alf'
+import * as Dialog from '#/components/Dialog'
+
+export function useTagMenuControl(): Dialog.DialogControlProps {
+ return {
+ id: '',
+ // @ts-ignore
+ ref: null,
+ open: () => {
+ throw new Error(`TagMenu controls are only available on native platforms`)
+ },
+ close: () => {
+ throw new Error(`TagMenu controls are only available on native platforms`)
+ },
+ }
+}
+
+export function TagMenu({
+ children,
+ tag,
+ authorHandle,
+}: React.PropsWithChildren<{
+ /**
+ * This should be the sanitized tag value from the facet itself, not the
+ * "display" value with a leading `#`.
+ */
+ tag: string
+ authorHandle?: string
+}>) {
+ const {_} = useLingui()
+ const navigation = useNavigation()
+ const {data: preferences} = usePreferencesQuery()
+ const {mutateAsync: upsertMutedWord, variables: optimisticUpsert} =
+ useUpsertMutedWordsMutation()
+ const {mutateAsync: removeMutedWord, variables: optimisticRemove} =
+ useRemoveMutedWordMutation()
+ const isMuted = Boolean(
+ (preferences?.mutedWords?.find(
+ m => m.value === tag && m.targets.includes('tag'),
+ ) ??
+ optimisticUpsert?.find(
+ m => m.value === tag && m.targets.includes('tag'),
+ )) &&
+ !(optimisticRemove?.value === tag),
+ )
+ const truncatedTag = '#' + enforceLen(tag, 15, true, 'middle')
+
+ const dropdownItems = React.useMemo(() => {
+ return [
+ {
+ label: _(msg`See ${truncatedTag} posts`),
+ onPress() {
+ navigation.push('Hashtag', {
+ tag: encodeURIComponent(tag),
+ })
+ },
+ testID: 'tagMenuSearch',
+ icon: {
+ ios: {
+ name: 'magnifyingglass',
+ },
+ android: '',
+ web: 'magnifying-glass',
+ },
+ },
+ authorHandle &&
+ !isInvalidHandle(authorHandle) && {
+ label: _(msg`See ${truncatedTag} posts by user`),
+ onPress() {
+ navigation.push('Hashtag', {
+ tag: encodeURIComponent(tag),
+ author: authorHandle,
+ })
+ },
+ testID: 'tagMenuSeachByUser',
+ icon: {
+ ios: {
+ name: 'magnifyingglass',
+ },
+ android: '',
+ web: ['far', 'user'],
+ },
+ },
+ preferences && {
+ label: 'separator',
+ },
+ preferences && {
+ label: isMuted
+ ? _(msg`Unmute ${truncatedTag}`)
+ : _(msg`Mute ${truncatedTag}`),
+ onPress() {
+ if (isMuted) {
+ removeMutedWord({value: tag, targets: ['tag']})
+ } else {
+ upsertMutedWord([{value: tag, targets: ['tag']}])
+ }
+ },
+ testID: 'tagMenuMute',
+ icon: {
+ ios: {
+ name: 'speaker.slash',
+ },
+ android: 'ic_menu_sort_alphabetically',
+ web: isMuted ? 'eye' : ['far', 'eye-slash'],
+ },
+ },
+ ].filter(Boolean)
+ }, [
+ _,
+ authorHandle,
+ isMuted,
+ navigation,
+ preferences,
+ tag,
+ truncatedTag,
+ upsertMutedWord,
+ removeMutedWord,
+ ])
+
+ return (
+
+
+ {children}
+
+
+ )
+}
diff --git a/src/components/dialogs/MutedWords.tsx b/src/components/dialogs/MutedWords.tsx
new file mode 100644
index 0000000000..658ba2aae0
--- /dev/null
+++ b/src/components/dialogs/MutedWords.tsx
@@ -0,0 +1,389 @@
+import React from 'react'
+import {Keyboard, View} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api'
+
+import {
+ usePreferencesQuery,
+ useUpsertMutedWordsMutation,
+ useRemoveMutedWordMutation,
+} from '#/state/queries/preferences'
+import {isNative} from '#/platform/detection'
+import {
+ atoms as a,
+ useTheme,
+ useBreakpoints,
+ ViewStyleProp,
+ web,
+ native,
+} from '#/alf'
+import {Text} from '#/components/Typography'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
+import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
+import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag'
+import {PageText_Stroke2_Corner0_Rounded as PageText} from '#/components/icons/PageText'
+import {Divider} from '#/components/Divider'
+import {Loader} from '#/components/Loader'
+import {logger} from '#/logger'
+import * as Dialog from '#/components/Dialog'
+import * as Toggle from '#/components/forms/Toggle'
+import * as Prompt from '#/components/Prompt'
+
+import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
+
+export function MutedWordsDialog() {
+ const {mutedWordsDialogControl: control} = useGlobalDialogsControlContext()
+ return (
+
+
+
+
+ )
+}
+
+function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) {
+ const t = useTheme()
+ const {_} = useLingui()
+ const {gtMobile} = useBreakpoints()
+ const {
+ isLoading: isPreferencesLoading,
+ data: preferences,
+ error: preferencesError,
+ } = usePreferencesQuery()
+ const {isPending, mutateAsync: addMutedWord} = useUpsertMutedWordsMutation()
+ const [field, setField] = React.useState('')
+ const [options, setOptions] = React.useState(['content'])
+ const [error, setError] = React.useState('')
+
+ const submit = React.useCallback(async () => {
+ const sanitizedValue = sanitizeMutedWordValue(field)
+ const targets = ['tag', options.includes('content') && 'content'].filter(
+ Boolean,
+ ) as AppBskyActorDefs.MutedWord['targets']
+
+ if (!sanitizedValue || !targets.length) {
+ setField('')
+ setError(_(msg`Please enter a valid word, tag, or phrase to mute`))
+ return
+ }
+
+ try {
+ // send raw value and rely on SDK as sanitization source of truth
+ await addMutedWord([{value: field, targets}])
+ setField('')
+ } catch (e: any) {
+ logger.error(`Failed to save muted word`, {message: e.message})
+ setError(e.message)
+ }
+ }, [_, field, options, addMutedWord, setField])
+
+ return (
+
+
+
+ Add muted words and tags
+
+
+
+ Posts can be muted based on their text, their tags, or both.
+
+
+
+
+ {
+ if (error) {
+ setError('')
+ }
+ setField(value)
+ }}
+ onSubmitEditing={submit}
+ />
+
+
+
+
+
+
+
+
+ Mute in text & tags
+
+
+
+
+
+
+
+
+
+
+
+ Mute in tags only
+
+
+
+
+
+
+
+
+
+
+ {error && (
+
+
+ {error}
+
+
+ )}
+
+
+
+ We recommend avoiding common words that appear in many posts,
+ since it can result in no posts being shown.
+
+
+
+
+
+
+
+
+ Your muted words
+
+
+ {isPreferencesLoading ? (
+
+ ) : preferencesError || !preferences ? (
+
+
+
+ We're sorry, but we weren't able to load your muted words at
+ this time. Please try again.
+
+
+
+ ) : preferences.mutedWords.length ? (
+ [...preferences.mutedWords]
+ .reverse()
+ .map((word, i) => (
+
+ ))
+ ) : (
+
+
+ You haven't muted any words or tags yet
+
+
+ )}
+
+
+ {isNative && }
+
+
+
+
+ )
+}
+
+function MutedWordRow({
+ style,
+ word,
+}: ViewStyleProp & {word: AppBskyActorDefs.MutedWord}) {
+ const t = useTheme()
+ const {_} = useLingui()
+ const {isPending, mutateAsync: removeMutedWord} = useRemoveMutedWordMutation()
+ const control = Prompt.usePromptControl()
+
+ const remove = React.useCallback(async () => {
+ control.close()
+ removeMutedWord(word)
+ }, [removeMutedWord, word, control])
+
+ return (
+ <>
+
+
+ Are you sure?
+
+
+
+ This will delete {word.value} from your muted words. You can always
+ add it back later.
+
+
+
+
+
+ Nevermind
+
+
+
+
+ Remove
+
+
+
+
+
+
+
+ {word.value}
+
+
+
+ {word.targets.map(target => (
+
+
+ {target === 'content' ? _(msg`text`) : _(msg`tag`)}
+
+
+ ))}
+
+
+
+
+ >
+ )
+}
+
+function TargetToggle({children}: React.PropsWithChildren<{}>) {
+ const t = useTheme()
+ const ctx = Toggle.useItemContext()
+ const {gtMobile} = useBreakpoints()
+ return (
+
+ {children}
+
+ )
+}
diff --git a/src/components/forms/DateField/index.android.tsx b/src/components/forms/DateField/index.android.tsx
index cddb643d61..451810a5ea 100644
--- a/src/components/forms/DateField/index.android.tsx
+++ b/src/components/forms/DateField/index.android.tsx
@@ -1,8 +1,5 @@
import React from 'react'
import {View, Pressable} from 'react-native'
-import DateTimePicker, {
- BaseProps as DateTimePickerProps,
-} from '@react-native-community/datetimepicker'
import {useTheme, atoms} from '#/alf'
import {Text} from '#/components/Typography'
@@ -15,6 +12,8 @@ import {
localizeDate,
toSimpleDateString,
} from '#/components/forms/DateField/utils'
+import DatePicker from 'react-native-date-picker'
+import {isAndroid} from 'platform/detection'
export * as utils from '#/components/forms/DateField/utils'
export const Label = TextField.Label
@@ -38,20 +37,20 @@ export function DateField({
const {chromeFocus, chromeError, chromeErrorHover} =
TextField.useSharedInputStyles()
- const onChangeInternal = React.useCallback<
- Required['onChange']
- >(
- (_event, date) => {
+ const onChangeInternal = React.useCallback(
+ (date: Date) => {
setOpen(false)
- if (date) {
- const formatted = toSimpleDateString(date)
- onChangeDate(formatted)
- }
+ const formatted = toSimpleDateString(date)
+ onChangeDate(formatted)
},
[onChangeDate, setOpen],
)
+ const onCancel = React.useCallback(() => {
+ setOpen(false)
+ }, [])
+
return (
{open && (
-
)}
diff --git a/src/components/forms/DateField/index.tsx b/src/components/forms/DateField/index.tsx
index e65936e0ea..49e47a01e3 100644
--- a/src/components/forms/DateField/index.tsx
+++ b/src/components/forms/DateField/index.tsx
@@ -1,13 +1,11 @@
import React from 'react'
import {View} from 'react-native'
-import DateTimePicker, {
- DateTimePickerEvent,
-} from '@react-native-community/datetimepicker'
import {useTheme, atoms} from '#/alf'
import * as TextField from '#/components/forms/TextField'
import {toSimpleDateString} from '#/components/forms/DateField/utils'
import {DateFieldProps} from '#/components/forms/DateField/types'
+import DatePicker from 'react-native-date-picker'
export * as utils from '#/components/forms/DateField/utils'
export const Label = TextField.Label
@@ -28,7 +26,7 @@ export function DateField({
const t = useTheme()
const onChangeInternal = React.useCallback(
- (event: DateTimePickerEvent, date: Date | undefined) => {
+ (date: Date | undefined) => {
if (date) {
const formatted = toSimpleDateString(date)
onChangeDate(formatted)
@@ -39,17 +37,15 @@ export function DateField({
return (
-
)
diff --git a/src/components/forms/TextField.tsx b/src/components/forms/TextField.tsx
index ebf2e47506..b37f4bfae9 100644
--- a/src/components/forms/TextField.tsx
+++ b/src/components/forms/TextField.tsx
@@ -10,7 +10,7 @@ import {
} from 'react-native'
import {HITSLOP_20} from 'lib/constants'
-import {useTheme, atoms as a, web, tokens, android} from '#/alf'
+import {useTheme, atoms as a, web, android} from '#/alf'
import {Text} from '#/components/Typography'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Props as SVGIconProps} from '#/components/icons/common'
@@ -72,7 +72,7 @@ export function Root({children, isInvalid = false}: RootProps) {
return (
inputRef.current?.focus(),
onMouseOver: onHoverIn,
@@ -110,7 +110,7 @@ export function useSharedInputStyles() {
{
backgroundColor:
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
- borderColor: tokens.color.red_500,
+ borderColor: t.palette.negative_500,
},
]
diff --git a/src/components/forms/Toggle.tsx b/src/components/forms/Toggle.tsx
index b83465dded..168639d6f8 100644
--- a/src/components/forms/Toggle.tsx
+++ b/src/components/forms/Toggle.tsx
@@ -13,6 +13,7 @@ import {
} from '#/alf'
import {Text} from '#/components/Typography'
import {useInteractionState} from '#/components/hooks/useInteractionState'
+import {CheckThick_Stroke2_Corner0_Rounded as Checkmark} from '#/components/icons/Check'
export type ItemState = {
name: string
@@ -314,7 +315,7 @@ export function createSharedToggleStyles({
if (isInvalid) {
base.push({
backgroundColor:
- t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
+ t.name === 'light' ? t.palette.negative_25 : t.palette.negative_975,
borderColor:
t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800,
})
@@ -323,7 +324,7 @@ export function createSharedToggleStyles({
baseHover.push({
backgroundColor:
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
- borderColor: t.palette.negative_500,
+ borderColor: t.palette.negative_600,
})
}
}
@@ -345,15 +346,14 @@ export function createSharedToggleStyles({
export function Checkbox() {
const t = useTheme()
const {selected, hovered, focused, disabled, isInvalid} = useItemContext()
- const {baseStyles, baseHoverStyles, indicatorStyles} =
- createSharedToggleStyles({
- theme: t,
- hovered,
- focused,
- selected,
- disabled,
- isInvalid,
- })
+ const {baseStyles, baseHoverStyles} = createSharedToggleStyles({
+ theme: t,
+ hovered,
+ focused,
+ selected,
+ disabled,
+ isInvalid,
+ })
return (
- {selected ? (
-
- ) : null}
+ {selected ? : null}
)
}
diff --git a/src/components/icons/Check.tsx b/src/components/icons/Check.tsx
index 24316c7849..fe9883baf8 100644
--- a/src/components/icons/Check.tsx
+++ b/src/components/icons/Check.tsx
@@ -3,3 +3,7 @@ import {createSinglePathSVG} from './TEMPLATE'
export const Check_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M21.59 3.193a1 1 0 0 1 .217 1.397l-11.706 16a1 1 0 0 1-1.429.193l-6.294-5a1 1 0 1 1 1.244-1.566l5.48 4.353 11.09-15.16a1 1 0 0 1 1.398-.217Z',
})
+
+export const CheckThick_Stroke2_Corner0_Rounded = createSinglePathSVG({
+ path: 'M21.474 2.98a2.5 2.5 0 0 1 .545 3.494l-10.222 14a2.5 2.5 0 0 1-3.528.52L2.49 16.617a2.5 2.5 0 0 1 3.018-3.986l3.75 2.84L17.98 3.525a2.5 2.5 0 0 1 3.493-.545Z',
+})
diff --git a/src/components/icons/Clipboard.tsx b/src/components/icons/Clipboard.tsx
new file mode 100644
index 0000000000..0135992b4c
--- /dev/null
+++ b/src/components/icons/Clipboard.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const Clipboard_Stroke2_Corner2_Rounded = createSinglePathSVG({
+ path: 'M8.17 4A3.001 3.001 0 0 1 11 2h2c1.306 0 2.418.835 2.83 2H17a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3h1.17ZM8 6H7a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1h-1v1a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V6Zm6 0V5a1 1 0 0 0-1-1h-2a1 1 0 0 0-1 1v1h4Z',
+})
diff --git a/src/components/icons/MagnifyingGlass2.tsx b/src/components/icons/MagnifyingGlass2.tsx
new file mode 100644
index 0000000000..3ca4034001
--- /dev/null
+++ b/src/components/icons/MagnifyingGlass2.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const MagnifyingGlass2_Stroke2_Corner0_Rounded = createSinglePathSVG({
+ path: 'M11 5a6 6 0 1 0 0 12 6 6 0 0 0 0-12Zm-8 6a8 8 0 1 1 14.32 4.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387A8 8 0 0 1 3 11Z',
+})
diff --git a/src/components/icons/Mute.tsx b/src/components/icons/Mute.tsx
new file mode 100644
index 0000000000..0065707870
--- /dev/null
+++ b/src/components/icons/Mute.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const Mute_Stroke2_Corner0_Rounded = createSinglePathSVG({
+ path: 'M20.707 3.293a1 1 0 0 1 0 1.414l-16 16a1 1 0 0 1-1.414-1.414l2.616-2.616A1.998 1.998 0 0 1 5 15V9a2 2 0 0 1 2-2h2.697l5.748-3.832A1 1 0 0 1 17 4v1.586l2.293-2.293a1 1 0 0 1 1.414 0ZM15 7.586 7.586 15H7V9h2.697a2 2 0 0 0 1.11-.336L15 5.87v1.717Zm2 3.657-2 2v4.888l-2.933-1.955-1.442 1.442 4.82 3.214A1 1 0 0 0 17 20v-8.757Z',
+})
diff --git a/src/components/icons/PageText.tsx b/src/components/icons/PageText.tsx
new file mode 100644
index 0000000000..25fbde3392
--- /dev/null
+++ b/src/components/icons/PageText.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const PageText_Stroke2_Corner0_Rounded = createSinglePathSVG({
+ path: 'M5 2a1 1 0 0 0-1 1v18a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H5Zm1 18V4h12v16H6Zm3-6a1 1 0 1 0 0 2h2a1 1 0 1 0 0-2H9Zm-1-3a1 1 0 0 1 1-1h6a1 1 0 1 1 0 2H9a1 1 0 0 1-1-1Zm1-5a1 1 0 0 0 0 2h6a1 1 0 1 0 0-2H9Z',
+})
diff --git a/src/components/moderation/ModerationDetailsDialog.tsx b/src/components/moderation/ModerationDetailsDialog.tsx
index 0f2eb53636..a0462e8573 100644
--- a/src/components/moderation/ModerationDetailsDialog.tsx
+++ b/src/components/moderation/ModerationDetailsDialog.tsx
@@ -94,6 +94,15 @@ function ModerationDetailsDialogInner({
name = _(msg`Account Muted`)
description = _(msg`You have muted this user.`)
}
+ // TODO
+ // } else if (cause.type === 'muted-word') {
+ // return {
+ // icon: EyeSlash,
+ // name: _(msg`Post hidden by muted word`),
+ // description: _(
+ // msg`You've chosen to hide a word or tag within this post.`,
+ // ),
+ // }
} else if (modcause.type === 'label') {
name = desc.name
description = desc.description
diff --git a/src/lib/__tests__/moderatePost_wrapped.test.ts b/src/lib/__tests__/moderatePost_wrapped.test.ts
new file mode 100644
index 0000000000..45566281af
--- /dev/null
+++ b/src/lib/__tests__/moderatePost_wrapped.test.ts
@@ -0,0 +1,692 @@
+import {describe, it, expect} from '@jest/globals'
+import {RichText} from '@atproto/api'
+
+import {hasMutedWord} from '../moderatePost_wrapped'
+
+describe(`hasMutedWord`, () => {
+ describe(`tags`, () => {
+ it(`match: outline tag`, () => {
+ const rt = new RichText({
+ text: `This is a post #inlineTag`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'outlineTag', targets: ['tag']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: ['outlineTag'],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: inline tag`, () => {
+ const rt = new RichText({
+ text: `This is a post #inlineTag`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'inlineTag', targets: ['tag']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: ['outlineTag'],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: content target matches inline tag`, () => {
+ const rt = new RichText({
+ text: `This is a post #inlineTag`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'inlineTag', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: ['outlineTag'],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`no match: only tag targets`, () => {
+ const rt = new RichText({
+ text: `This is a post`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'inlineTag', targets: ['tag']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+ })
+
+ describe(`early exits`, () => {
+ it(`match: single character åø`, () => {
+ /**
+ * @see https://bsky.app/profile/mukuuji.bsky.social/post/3klji4fvsdk2c
+ */
+ const rt = new RichText({
+ text: `ę¹ååøęć§ć`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'åø', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`no match: long muted word, short post`, () => {
+ const rt = new RichText({
+ text: `hey`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'politics', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+
+ it(`match: exact text`, () => {
+ const rt = new RichText({
+ text: `javascript`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'javascript', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`general content`, () => {
+ it(`match: word within post`, () => {
+ const rt = new RichText({
+ text: `This is a post about javascript`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'javascript', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`no match: partial word`, () => {
+ const rt = new RichText({
+ text: `Use your brain, Eric`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'ai', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+
+ it(`match: multiline`, () => {
+ const rt = new RichText({
+ text: `Use your\n\tbrain, Eric`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'brain', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: :)`, () => {
+ const rt = new RichText({
+ text: `So happy :)`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: `:)`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`punctuation semi-fuzzy`, () => {
+ describe(`yay!`, () => {
+ const rt = new RichText({
+ text: `We're federating, yay!`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: yay!`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'yay!', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: yay`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'yay', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`y!ppee!!`, () => {
+ const rt = new RichText({
+ text: `We're federating, y!ppee!!`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: y!ppee`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'y!ppee', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ // single exclamation point, source has double
+ it(`no match: y!ppee!`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'y!ppee!', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`Why so S@assy?`, () => {
+ const rt = new RichText({
+ text: `Why so S@assy?`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: S@assy`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'S@assy', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: s@assy`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 's@assy', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`New York Times`, () => {
+ const rt = new RichText({
+ text: `New York Times`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ // case insensitive
+ it(`match: new york times`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'new york times', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`!command`, () => {
+ const rt = new RichText({
+ text: `Idk maybe a bot !command`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: !command`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `!command`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: command`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `command`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`no match: !command`, () => {
+ const rt = new RichText({
+ text: `Idk maybe a bot command`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ const match = hasMutedWord({
+ mutedWords: [{value: `!command`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+ })
+
+ describe(`e/acc`, () => {
+ const rt = new RichText({
+ text: `I'm e/acc pilled`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: e/acc`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `e/acc`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: acc`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `acc`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`super-bad`, () => {
+ const rt = new RichText({
+ text: `I'm super-bad`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: super-bad`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `super-bad`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: super`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `super`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: super bad`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `super bad`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: superbad`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `superbad`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+ })
+
+ describe(`idk_what_this_would_be`, () => {
+ const rt = new RichText({
+ text: `Weird post with idk_what_this_would_be`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: idk what this would be`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `idk what this would be`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`no match: idk what this would be for`, () => {
+ // extra word
+ const match = hasMutedWord({
+ mutedWords: [
+ {value: `idk what this would be for`, targets: ['content']},
+ ],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+
+ it(`match: idk`, () => {
+ // extra word
+ const match = hasMutedWord({
+ mutedWords: [{value: `idk`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: idkwhatthiswouldbe`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `idkwhatthiswouldbe`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(false)
+ })
+ })
+
+ describe(`parentheses`, () => {
+ const rt = new RichText({
+ text: `Post with context(iykyk)`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: context(iykyk)`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `context(iykyk)`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: context`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `context`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: iykyk`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `iykyk`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: (iykyk)`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `(iykyk)`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+
+ describe(`š¦`, () => {
+ const rt = new RichText({
+ text: `Post with š¦`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: š¦`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: `š¦`, targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+ })
+
+ describe(`phrases`, () => {
+ describe(`I like turtles, or how I learned to stop worrying and love the internet.`, () => {
+ const rt = new RichText({
+ text: `I like turtles, or how I learned to stop worrying and love the internet.`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ it(`match: stop worrying`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'stop worrying', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`match: turtles, or how`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'turtles, or how', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+ })
+
+ describe(`languages without spaces`, () => {
+ // I love turtles, or how I learned to stop worrying and love the internet
+ describe(`ē§ćÆć«ć”ć儽ćć§ććć¾ććÆć©ć®ććć«ćć¦åæé
ććć®ćććć¦ć¤ć³ćæć¼ććććęććććć«ćŖć£ćć®ć`, () => {
+ const rt = new RichText({
+ text: `ē§ćÆć«ć”ć儽ćć§ććć¾ććÆć©ć®ććć«ćć¦åæé
ććć®ćććć¦ć¤ć³ćæć¼ććććęććććć«ćŖć£ćć®ć`,
+ })
+ rt.detectFacetsWithoutResolution()
+
+ // internet
+ it(`match: ć¤ć³ćæć¼ććć`, () => {
+ const match = hasMutedWord({
+ mutedWords: [{value: 'ć¤ć³ćæć¼ććć', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ languages: ['ja'],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+ })
+ })
+
+ describe(`doesn't mute own post`, () => {
+ it(`does mute if it isn't own post`, () => {
+ const rt = new RichText({
+ text: `Mute words!`,
+ })
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'words', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: false,
+ })
+
+ expect(match).toBe(true)
+ })
+
+ it(`doesn't mute own post when muted word is in text`, () => {
+ const rt = new RichText({
+ text: `Mute words!`,
+ })
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'words', targets: ['content']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: true,
+ })
+
+ expect(match).toBe(false)
+ })
+
+ it(`doesn't mute own post when muted word is in tags`, () => {
+ const rt = new RichText({
+ text: `Mute #words!`,
+ })
+
+ const match = hasMutedWord({
+ mutedWords: [{value: 'words', targets: ['tags']}],
+ text: rt.text,
+ facets: rt.facets,
+ outlineTags: [],
+ isOwnPost: true,
+ })
+
+ expect(match).toBe(false)
+ })
+ })
+})
diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts
index 440dfa5ee3..5fb7fe50e6 100644
--- a/src/lib/api/index.ts
+++ b/src/lib/api/index.ts
@@ -104,18 +104,18 @@ export async function post(agent: BskyAgent, opts: PostOpts) {
// add image embed if present
if (opts.images?.length) {
- logger.info(`Uploading images`, {
+ logger.debug(`Uploading images`, {
count: opts.images.length,
})
const images: AppBskyEmbedImages.Image[] = []
for (const image of opts.images) {
opts.onStateChange?.(`Uploading image #${images.length + 1}...`)
- logger.info(`Compressing image`)
+ logger.debug(`Compressing image`)
await image.compress()
const path = image.compressed?.path ?? image.path
const {width, height} = image.compressed || image
- logger.info(`Uploading image`)
+ logger.debug(`Uploading image`)
const res = await uploadBlob(agent, path, 'image/jpeg')
images.push({
image: res.data.blob,
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index c8e5273d47..e868443950 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -75,3 +75,9 @@ export const HITSLOP_20 = createHitslop(20)
export const HITSLOP_30 = createHitslop(30)
export const BACK_HITSLOP = HITSLOP_30
export const MAX_POST_LINES = 25
+
+export const BSKY_FEED_OWNER_DIDS = [
+ 'did:plc:z72i7hdynmk6r22z27h6tvur',
+ 'did:plc:vpkhqolt662uhesyj6nxm7ys',
+ 'did:plc:q6gjnaw2blty4crticxkmujt',
+]
diff --git a/src/lib/hooks/useInitialNumToRender.ts b/src/lib/hooks/useInitialNumToRender.ts
new file mode 100644
index 0000000000..942f0404ab
--- /dev/null
+++ b/src/lib/hooks/useInitialNumToRender.ts
@@ -0,0 +1,11 @@
+import React from 'react'
+import {Dimensions} from 'react-native'
+
+const MIN_POST_HEIGHT = 100
+
+export function useInitialNumToRender(minItemHeight: number = MIN_POST_HEIGHT) {
+ return React.useMemo(() => {
+ const screenHeight = Dimensions.get('window').height
+ return Math.ceil(screenHeight / minItemHeight) + 1
+ }, [minItemHeight])
+}
diff --git a/src/lib/hooks/useIntentHandler.ts b/src/lib/hooks/useIntentHandler.ts
new file mode 100644
index 0000000000..8741530b50
--- /dev/null
+++ b/src/lib/hooks/useIntentHandler.ts
@@ -0,0 +1,93 @@
+import React from 'react'
+import * as Linking from 'expo-linking'
+import {isNative} from 'platform/detection'
+import {useComposerControls} from 'state/shell'
+import {useSession} from 'state/session'
+import {useCloseAllActiveElements} from 'state/util'
+
+type IntentType = 'compose'
+
+const VALID_IMAGE_REGEX = /^[\w.:\-_/]+\|\d+(\.\d+)?\|\d+(\.\d+)?$/
+
+export function useIntentHandler() {
+ const incomingUrl = Linking.useURL()
+ const composeIntent = useComposeIntent()
+
+ React.useEffect(() => {
+ const handleIncomingURL = (url: string) => {
+ // We want to be able to support bluesky:// deeplinks. It's unnatural for someone to use a deeplink with three
+ // slashes, like bluesky:///intent/follow. However, supporting just two slashes causes us to have to take care
+ // of two cases when parsing the url. If we ensure there is a third slash, we can always ensure the first
+ // path parameter is in pathname rather than in hostname.
+ if (url.startsWith('bluesky://') && !url.startsWith('bluesky:///')) {
+ url = url.replace('bluesky://', 'bluesky:///')
+ }
+
+ const urlp = new URL(url)
+ const [_, intent, intentType] = urlp.pathname.split('/')
+
+ // On native, our links look like bluesky://intent/SomeIntent, so we have to check the hostname for the
+ // intent check. On web, we have to check the first part of the path since we have an actual hostname
+ const isIntent = intent === 'intent'
+ const params = urlp.searchParams
+
+ if (!isIntent) return
+
+ switch (intentType as IntentType) {
+ case 'compose': {
+ composeIntent({
+ text: params.get('text'),
+ imageUrisStr: params.get('imageUris'),
+ })
+ }
+ }
+ }
+
+ if (incomingUrl) handleIncomingURL(incomingUrl)
+ }, [incomingUrl, composeIntent])
+}
+
+function useComposeIntent() {
+ const closeAllActiveElements = useCloseAllActiveElements()
+ const {openComposer} = useComposerControls()
+ const {hasSession} = useSession()
+
+ return React.useCallback(
+ ({
+ text,
+ imageUrisStr,
+ }: {
+ text: string | null
+ imageUrisStr: string | null // unused for right now, will be used later with intents
+ }) => {
+ if (!hasSession) return
+
+ closeAllActiveElements()
+
+ const imageUris = imageUrisStr
+ ?.split(',')
+ .filter(part => {
+ // For some security, we're going to filter out any image uri that is external. We don't want someone to
+ // be able to provide some link like "bluesky://intent/compose?imageUris=https://IHaveYourIpNow.com/image.jpeg
+ // and we load that image
+ if (part.includes('https://') || part.includes('http://')) {
+ return false
+ }
+ // We also should just filter out cases that don't have all the info we need
+ return VALID_IMAGE_REGEX.test(part)
+ })
+ .map(part => {
+ const [uri, width, height] = part.split('|')
+ return {uri, width: Number(width), height: Number(height)}
+ })
+
+ setTimeout(() => {
+ openComposer({
+ text: text ?? undefined,
+ imageUris: isNative ? imageUris : undefined,
+ })
+ }, 500)
+ },
+ [hasSession, closeAllActiveElements, openComposer],
+ )
+}
diff --git a/src/lib/moderatePost_wrapped.ts b/src/lib/moderatePost_wrapped.ts
index 90581ff31c..0037d4a7a9 100644
--- a/src/lib/moderatePost_wrapped.ts
+++ b/src/lib/moderatePost_wrapped.ts
@@ -1,8 +1,144 @@
-import {moderatePost} from '@atproto/api'
+import {
+ // AppBskyEmbedRecord,
+ // AppBskyEmbedRecordWithMedia,
+ moderatePost,
+ AppBskyActorDefs,
+ // AppBskyFeedPost,
+ AppBskyRichtextFacet,
+ // AppBskyEmbedImages,
+ // AppBskyEmbedExternal,
+} from '@atproto/api'
type ModeratePost = typeof moderatePost
type Options = Parameters[1] & {
hiddenPosts?: string[]
+ mutedWords?: AppBskyActorDefs.MutedWord[]
+}
+
+const REGEX = {
+ LEADING_TRAILING_PUNCTUATION: /(?:^\p{P}+|\p{P}+$)/gu,
+ ESCAPE: /[[\]{}()*+?.\\^$|\s]/g,
+ SEPARATORS: /[\/\-\ā\ā\(\)\[\]\_]+/g,
+ WORD_BOUNDARY: /[\s\n\t\r\f\v]+?/g,
+}
+
+/**
+ * List of 2-letter lang codes for languages that either don't use spaces, or
+ * don't use spaces in a way conducive to word-based filtering.
+ *
+ * For these, we use a simple `String.includes` to check for a match.
+ */
+const LANGUAGE_EXCEPTIONS = [
+ 'ja', // Japanese
+ 'zh', // Chinese
+ 'ko', // Korean
+ 'th', // Thai
+ 'vi', // Vietnamese
+]
+
+export function hasMutedWord({
+ mutedWords,
+ text,
+ facets,
+ outlineTags,
+ languages,
+ isOwnPost,
+}: {
+ mutedWords: AppBskyActorDefs.MutedWord[]
+ text: string
+ facets?: AppBskyRichtextFacet.Main[]
+ outlineTags?: string[]
+ languages?: string[]
+ isOwnPost: boolean
+}) {
+ if (isOwnPost) return false
+
+ const exception = LANGUAGE_EXCEPTIONS.includes(languages?.[0] || '')
+ const tags = ([] as string[])
+ .concat(outlineTags || [])
+ .concat(
+ facets
+ ?.filter(facet => {
+ return facet.features.find(feature =>
+ AppBskyRichtextFacet.isTag(feature),
+ )
+ })
+ .map(t => t.features[0].tag as string) || [],
+ )
+ .map(t => t.toLowerCase())
+
+ for (const mute of mutedWords) {
+ const mutedWord = mute.value.toLowerCase()
+ const postText = text.toLowerCase()
+
+ // `content` applies to tags as well
+ if (tags.includes(mutedWord)) return true
+ // rest of the checks are for `content` only
+ if (!mute.targets.includes('content')) continue
+ // single character or other exception, has to use includes
+ if ((mutedWord.length === 1 || exception) && postText.includes(mutedWord))
+ return true
+ // too long
+ if (mutedWord.length > postText.length) continue
+ // exact match
+ if (mutedWord === postText) return true
+ // any muted phrase with space or punctuation
+ if (/(?:\s|\p{P})+?/u.test(mutedWord) && postText.includes(mutedWord))
+ return true
+
+ // check individual character groups
+ const words = postText.split(REGEX.WORD_BOUNDARY)
+ for (const word of words) {
+ if (word === mutedWord) return true
+
+ // compare word without leading/trailing punctuation, but allow internal
+ // punctuation (such as `s@ssy`)
+ const wordTrimmedPunctuation = word.replace(
+ REGEX.LEADING_TRAILING_PUNCTUATION,
+ '',
+ )
+
+ if (mutedWord === wordTrimmedPunctuation) return true
+ if (mutedWord.length > wordTrimmedPunctuation.length) continue
+
+ // handle hyphenated, slash separated words, etc
+ if (REGEX.SEPARATORS.test(wordTrimmedPunctuation)) {
+ // check against full normalized phrase
+ const wordNormalizedSeparators = wordTrimmedPunctuation.replace(
+ REGEX.SEPARATORS,
+ ' ',
+ )
+ const mutedWordNormalizedSeparators = mutedWord.replace(
+ REGEX.SEPARATORS,
+ ' ',
+ )
+ // hyphenated (or other sep) to spaced words
+ if (wordNormalizedSeparators === mutedWordNormalizedSeparators)
+ return true
+
+ /* Disabled for now e.g. `super-cool` to `supercool`
+ const wordNormalizedCompressed = wordNormalizedSeparators.replace(
+ REGEX.WORD_BOUNDARY,
+ '',
+ )
+ const mutedWordNormalizedCompressed =
+ mutedWordNormalizedSeparators.replace(/\s+?/g, '')
+ // hyphenated (or other sep) to non-hyphenated contiguous word
+ if (mutedWordNormalizedCompressed === wordNormalizedCompressed)
+ return true
+ */
+
+ // then individual parts of separated phrases/words
+ const wordParts = wordTrimmedPunctuation.split(REGEX.SEPARATORS)
+ for (const wp of wordParts) {
+ // still retain internal punctuation
+ if (wp === mutedWord) return true
+ }
+ }
+ }
+ }
+
+ return false
}
export function moderatePost_wrapped(
@@ -12,4 +148,238 @@ export function moderatePost_wrapped(
const moderation = moderatePost(subject, opts)
moderation.addHidden(opts.hiddenPosts?.includes(subject.uri) || false)
return moderation
+ /* TODO
+ const {hiddenPosts = [], mutedWords = [], ...options} = opts
+ const moderations = moderatePost(subject, options)
+ const isOwnPost = subject.author.did === opts.userDid
+
+ if (hiddenPosts.includes(subject.uri)) {
+ moderations.content.filter = true
+ moderations.content.blur = true
+ if (!moderations.content.cause) {
+ moderations.content.cause = {
+ // @ts-ignore Temporary extension to the moderation system -prf
+ type: 'post-hidden',
+ source: {type: 'user'},
+ priority: 1,
+ }
+ }
+ }
+
+ if (AppBskyFeedPost.isRecord(subject.record)) {
+ let muted = hasMutedWord({
+ mutedWords,
+ text: subject.record.text,
+ facets: subject.record.facets || [],
+ outlineTags: subject.record.tags || [],
+ languages: subject.record.langs,
+ isOwnPost,
+ })
+
+ if (
+ subject.record.embed &&
+ AppBskyEmbedImages.isMain(subject.record.embed)
+ ) {
+ for (const image of subject.record.embed.images) {
+ muted =
+ muted ||
+ hasMutedWord({
+ mutedWords,
+ text: image.alt,
+ facets: [],
+ outlineTags: [],
+ languages: subject.record.langs,
+ isOwnPost,
+ })
+ }
+ }
+
+ if (muted) {
+ moderations.content.filter = true
+ moderations.content.blur = true
+ if (!moderations.content.cause) {
+ moderations.content.cause = {
+ // @ts-ignore Temporary extension to the moderation system -prf
+ type: 'muted-word',
+ source: {type: 'user'},
+ priority: 1,
+ }
+ }
+ }
+ }
+
+ if (subject.embed) {
+ let embedHidden = false
+ let embedMuted = false
+ let externalMuted = false
+
+ if (AppBskyEmbedRecord.isViewRecord(subject.embed.record)) {
+ embedHidden = hiddenPosts.includes(subject.embed.record.uri)
+ }
+ if (
+ AppBskyEmbedRecordWithMedia.isView(subject.embed) &&
+ AppBskyEmbedRecord.isViewRecord(subject.embed.record.record)
+ ) {
+ embedHidden = hiddenPosts.includes(subject.embed.record.record.uri)
+ }
+
+ if (AppBskyEmbedRecord.isViewRecord(subject.embed.record)) {
+ if (AppBskyFeedPost.isRecord(subject.embed.record.value)) {
+ const embeddedPost = subject.embed.record.value
+
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: embeddedPost.text,
+ facets: embeddedPost.facets,
+ outlineTags: embeddedPost.tags,
+ languages: embeddedPost.langs,
+ isOwnPost,
+ })
+
+ if (AppBskyEmbedImages.isMain(embeddedPost.embed)) {
+ for (const image of embeddedPost.embed.images) {
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: image.alt,
+ facets: [],
+ outlineTags: [],
+ languages: embeddedPost.langs,
+ isOwnPost,
+ })
+ }
+ }
+
+ if (AppBskyEmbedExternal.isMain(embeddedPost.embed)) {
+ const {external} = embeddedPost.embed
+
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: external.title + ' ' + external.description,
+ facets: [],
+ outlineTags: [],
+ languages: [],
+ isOwnPost,
+ })
+ }
+
+ if (AppBskyEmbedRecordWithMedia.isMain(embeddedPost.embed)) {
+ if (AppBskyEmbedExternal.isMain(embeddedPost.embed.media)) {
+ const {external} = embeddedPost.embed.media
+
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: external.title + ' ' + external.description,
+ facets: [],
+ outlineTags: [],
+ languages: [],
+ isOwnPost,
+ })
+ }
+
+ if (AppBskyEmbedImages.isMain(embeddedPost.embed.media)) {
+ for (const image of embeddedPost.embed.media.images) {
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: image.alt,
+ facets: [],
+ outlineTags: [],
+ languages: AppBskyFeedPost.isRecord(embeddedPost.record)
+ ? embeddedPost.langs
+ : [],
+ isOwnPost,
+ })
+ }
+ }
+ }
+ }
+ }
+
+ if (AppBskyEmbedExternal.isView(subject.embed)) {
+ const {external} = subject.embed
+
+ externalMuted =
+ externalMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: external.title + ' ' + external.description,
+ facets: [],
+ outlineTags: [],
+ languages: [],
+ isOwnPost,
+ })
+ }
+
+ if (
+ AppBskyEmbedRecordWithMedia.isView(subject.embed) &&
+ AppBskyEmbedRecord.isViewRecord(subject.embed.record.record)
+ ) {
+ if (AppBskyFeedPost.isRecord(subject.embed.record.record.value)) {
+ const post = subject.embed.record.record.value
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: post.text,
+ facets: post.facets,
+ outlineTags: post.tags,
+ languages: post.langs,
+ isOwnPost,
+ })
+ }
+
+ if (AppBskyEmbedImages.isView(subject.embed.media)) {
+ for (const image of subject.embed.media.images) {
+ embedMuted =
+ embedMuted ||
+ hasMutedWord({
+ mutedWords,
+ text: image.alt,
+ facets: [],
+ outlineTags: [],
+ languages: AppBskyFeedPost.isRecord(subject.record)
+ ? subject.record.langs
+ : [],
+ isOwnPost,
+ })
+ }
+ }
+ }
+
+ if (embedHidden) {
+ moderations.embed.filter = true
+ moderations.embed.blur = true
+ if (!moderations.embed.cause) {
+ moderations.embed.cause = {
+ // @ts-ignore Temporary extension to the moderation system -prf
+ type: 'post-hidden',
+ source: {type: 'user'},
+ priority: 1,
+ }
+ }
+ } else if (externalMuted || embedMuted) {
+ moderations.content.filter = true
+ moderations.content.blur = true
+ if (!moderations.content.cause) {
+ moderations.content.cause = {
+ // @ts-ignore Temporary extension to the moderation system -prf
+ type: 'muted-word',
+ source: {type: 'user'},
+ priority: 1,
+ }
+ }
+ }
+ }
+
+ return moderations
+ */
}
diff --git a/src/lib/moderation/useModerationCauseDescription.ts b/src/lib/moderation/useModerationCauseDescription.ts
index de2e9788f8..882480491c 100644
--- a/src/lib/moderation/useModerationCauseDescription.ts
+++ b/src/lib/moderation/useModerationCauseDescription.ts
@@ -84,6 +84,16 @@ export function useModerationCauseDescription(
}
}
}
+ // TODO
+ // if (cause.type === 'muted-word') {
+ // return {
+ // icon: EyeSlash,
+ // name: _(msg`Post hidden by muted word`),
+ // description: _(
+ // msg`You've chosen to hide a word or tag within this post.`,
+ // ),
+ // }
+ // }
// @ts-ignore Temporary extension to the moderation system -prf
if (cause.type === 'hidden') {
return {
diff --git a/src/lib/routes/links.ts b/src/lib/routes/links.ts
index 538f30cd31..9dfdab909b 100644
--- a/src/lib/routes/links.ts
+++ b/src/lib/routes/links.ts
@@ -25,3 +25,13 @@ export function makeCustomFeedLink(
export function makeListLink(did: string, rkey: string, ...segments: string[]) {
return [`/profile`, did, 'lists', rkey, ...segments].join('/')
}
+
+export function makeTagLink(did: string) {
+ return `/search?q=${encodeURIComponent(did)}`
+}
+
+export function makeSearchLink(props: {query: string; from?: 'me' | string}) {
+ return `/search?q=${encodeURIComponent(
+ props.query + (props.from ? ` from:${props.from}` : ''),
+ )}`
+}
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
index c4bf4dd0c2..59495401d5 100644
--- a/src/lib/routes/types.ts
+++ b/src/lib/routes/types.ts
@@ -34,6 +34,8 @@ export type CommonNavigatorParams = {
PreferencesFollowingFeed: undefined
PreferencesThreads: undefined
PreferencesExternalEmbeds: undefined
+ Search: {q?: string}
+ Hashtag: {tag: string; author?: string}
}
export type BottomTabNavigatorParams = CommonNavigatorParams & {
@@ -69,6 +71,7 @@ export type FlatNavigatorParams = CommonNavigatorParams & {
Search: {q?: string}
Feeds: undefined
Notifications: undefined
+ Hashtag: {tag: string; author?: string}
}
export type AllNavigatorParams = CommonNavigatorParams & {
@@ -81,6 +84,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
NotificationsTab: undefined
Notifications: undefined
MyProfileTab: undefined
+ Hashtag: {tag: string; author?: string}
}
// NOTE
diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx
new file mode 100644
index 0000000000..43822dda85
--- /dev/null
+++ b/src/lib/statsig/statsig.tsx
@@ -0,0 +1,63 @@
+import React from 'react'
+import {
+ Statsig,
+ StatsigProvider,
+ useGate as useStatsigGate,
+} from 'statsig-react-native-expo'
+import {useSession} from '../../state/session'
+import {sha256} from 'js-sha256'
+
+const statsigOptions = {
+ environment: {
+ tier: process.env.NODE_ENV === 'development' ? 'development' : 'production',
+ },
+ // Don't block on waiting for network. The fetched config will kick in on next load.
+ // This ensures the UI is always consistent and doesn't update mid-session.
+ // Note this makes cold load (no local storage) and private mode return `false` for all gates.
+ initTimeoutMs: 1,
+}
+
+export function logEvent(
+ eventName: string,
+ value?: string | number | null,
+ metadata?: Record | null,
+) {
+ Statsig.logEvent(eventName, value, metadata)
+}
+
+export function useGate(gateName: string) {
+ const {isLoading, value} = useStatsigGate(gateName)
+ if (isLoading) {
+ // This should not happen because of waitForInitialization={true}.
+ console.error('Did not expected isLoading to ever be true.')
+ }
+ return value
+}
+
+function toStatsigUser(did: string | undefined) {
+ let userID: string | undefined
+ if (did) {
+ userID = sha256(did)
+ }
+ return {userID}
+}
+
+export function Provider({children}: {children: React.ReactNode}) {
+ const {currentAccount} = useSession()
+ const currentStatsigUser = React.useMemo(
+ () => toStatsigUser(currentAccount?.did),
+ [currentAccount?.did],
+ )
+ return (
+
+ {children}
+
+ )
+}
diff --git a/src/lib/statsig/statsig.web.tsx b/src/lib/statsig/statsig.web.tsx
new file mode 100644
index 0000000000..fc66e8d9fd
--- /dev/null
+++ b/src/lib/statsig/statsig.web.tsx
@@ -0,0 +1,63 @@
+import React from 'react'
+import {
+ Statsig,
+ StatsigProvider,
+ useGate as useStatsigGate,
+} from 'statsig-react'
+import {useSession} from '../../state/session'
+import {sha256} from 'js-sha256'
+
+const statsigOptions = {
+ environment: {
+ tier: process.env.NODE_ENV === 'development' ? 'development' : 'production',
+ },
+ // Don't block on waiting for network. The fetched config will kick in on next load.
+ // This ensures the UI is always consistent and doesn't update mid-session.
+ // Note this makes cold load (no local storage) and private mode return `false` for all gates.
+ initTimeoutMs: 1,
+}
+
+export function logEvent(
+ eventName: string,
+ value?: string | number | null,
+ metadata?: Record | null,
+) {
+ Statsig.logEvent(eventName, value, metadata)
+}
+
+export function useGate(gateName: string) {
+ const {isLoading, value} = useStatsigGate(gateName)
+ if (isLoading) {
+ // This should not happen because of waitForInitialization={true}.
+ console.error('Did not expected isLoading to ever be true.')
+ }
+ return value
+}
+
+function toStatsigUser(did: string | undefined) {
+ let userID: string | undefined
+ if (did) {
+ userID = sha256(did)
+ }
+ return {userID}
+}
+
+export function Provider({children}: {children: React.ReactNode}) {
+ const {currentAccount} = useSession()
+ const currentStatsigUser = React.useMemo(
+ () => toStatsigUser(currentAccount?.did),
+ [currentAccount?.did],
+ )
+ return (
+
+ {children}
+
+ )
+}
diff --git a/src/lib/strings/helpers.ts b/src/lib/strings/helpers.ts
index e2abe90195..de4562d2c8 100644
--- a/src/lib/strings/helpers.ts
+++ b/src/lib/strings/helpers.ts
@@ -8,10 +8,27 @@ export function pluralize(n: number, base: string, plural?: string): string {
return base + 's'
}
-export function enforceLen(str: string, len: number, ellipsis = false): string {
+export function enforceLen(
+ str: string,
+ len: number,
+ ellipsis = false,
+ mode: 'end' | 'middle' = 'end',
+): string {
str = str || ''
if (str.length > len) {
- return str.slice(0, len) + (ellipsis ? '...' : '')
+ if (ellipsis) {
+ if (mode === 'end') {
+ return str.slice(0, len) + 'ā¦'
+ } else if (mode === 'middle') {
+ const half = Math.floor(len / 2)
+ return str.slice(0, half) + 'ā¦' + str.slice(-half)
+ } else {
+ // fallback
+ return str.slice(0, len)
+ }
+ } else {
+ return str.slice(0, len)
+ }
}
return str
}
diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts
index ef341154df..7729e4a382 100644
--- a/src/lib/strings/url-helpers.ts
+++ b/src/lib/strings/url-helpers.ts
@@ -148,6 +148,11 @@ export function feedUriToHref(url: string): string {
export function linkRequiresWarning(uri: string, label: string) {
const labelDomain = labelToDomain(label)
+ // If the uri started with a / we know it is internal.
+ if (uri.startsWith('/')) {
+ return false
+ }
+
let urip
try {
urip = new URL(uri)
@@ -156,18 +161,15 @@ export function linkRequiresWarning(uri: string, label: string) {
}
const host = urip.hostname.toLowerCase()
-
- if (host === 'bsky.app') {
+ // Hosts that end with bsky.app or bsky.social should be trusted by default.
+ if (
+ host.endsWith('bsky.app') ||
+ host.endsWith('bsky.social') ||
+ host.endsWith('blueskyweb.xyz')
+ ) {
// if this is a link to internal content,
// warn if it represents itself as a URL to another app
- if (
- labelDomain &&
- labelDomain !== 'bsky.app' &&
- isPossiblyAUrl(labelDomain)
- ) {
- return true
- }
- return false
+ return !!labelDomain && labelDomain !== host && isPossiblyAUrl(labelDomain)
} else {
// if this is a link to external content,
// warn if the label doesnt match the target
diff --git a/src/lib/themes.ts b/src/lib/themes.ts
index 135d50ab66..bd75aabea6 100644
--- a/src/lib/themes.ts
+++ b/src/lib/themes.ts
@@ -357,8 +357,8 @@ export const dimTheme: Theme = {
textVeryLight: dimPalette.contrast_400,
replyLine: dimPalette.contrast_200,
replyLineDot: dimPalette.contrast_200,
- unreadNotifBg: `hsl(211, 48%, 17%)`,
- unreadNotifBorder: `hsl(211, 48%, 30%)`,
+ unreadNotifBg: dimPalette.primary_975,
+ unreadNotifBorder: dimPalette.primary_900,
postCtrl: dimPalette.contrast_500,
brandText: dimPalette.primary_500,
emptyStateIcon: dimPalette.contrast_300,
diff --git a/src/locale/locales/ca/messages.po b/src/locale/locales/ca/messages.po
index 9f7f853c59..927599ab43 100644
--- a/src/locale/locales/ca/messages.po
+++ b/src/locale/locales/ca/messages.po
@@ -91,7 +91,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Hi ha una nova versió d'aquesta aplicació. Actualitza-la per continuar."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "Accedeix als enllaços de navegació i configuració"
@@ -142,6 +142,7 @@ msgstr "Compte desbloquejat"
msgid "Account unmuted"
msgstr "Compte no silenciat"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -183,14 +184,22 @@ msgstr "Afegeix detalls"
msgid "Add details to report"
msgstr "Afegeix detalls a l'informe"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Afegeix una targeta a l'enllaƧ"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Afegeix una targeta a l'enllaƧ:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "Afegeix el següent registre DNS al teu domini:"
@@ -310,7 +319,7 @@ msgstr "Configuració de la contrasenya d'aplicació"
msgid "App Passwords"
msgstr "Contrasenyes de l'aplicació"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "Advertència d'apel·lació sobre el contingut"
@@ -337,15 +346,16 @@ msgstr "AparenƧa"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "Confirmes que vols eliminar la contrasenya de l'aplicació \"{name}\"?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "Confirmes que vols descartar aquest esborrany?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "Ho confirmes?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "Ho confirmes? Aquesta acció no es pot desfer."
@@ -367,15 +377,15 @@ msgstr "Nuesa artĆstica o no eròtica."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "Endarrere"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "Endarrere"
@@ -423,7 +433,7 @@ msgstr "Bloqueja la llista"
msgid "Blocked"
msgstr "Bloquejada"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Comptes bloquejats"
@@ -482,7 +492,7 @@ msgstr "Bluesky és públic."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky utilitza les invitacions per construir una comunitat saludable. Si no coneixes ningĆŗ amb invitacions, pots apuntar-te a la llista d'espera i te n'enviarem una aviat."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky no mostrarà el teu perfil ni les publicacions als usuaris que no estiguin registrats. Altres aplicacions poden no seguir aquesta demanda. Això no fa que el teu compte sigui privat."
@@ -534,8 +544,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Només pot tenir lletres, números, espais, guions i guions baixos. Ha de tenir almenys 4 carà cters i no més de 32."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -549,7 +559,7 @@ msgstr "Només pot tenir lletres, números, espais, guions i guions baixos. Ha d
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "CancelĀ·la"
@@ -704,7 +714,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Esborra totes les dades emmagatzemades (i desprƩs reinicia)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Esborra la cerca"
@@ -712,6 +722,11 @@ msgstr "Esborra la cerca"
msgid "click here"
msgstr "clica aquĆ"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -742,11 +757,15 @@ msgstr "Tanca la imatge"
msgid "Close image viewer"
msgstr "Tanca el visor d'imatges"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "Tanca el peu de la navegació"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "Tanca la barra de navegació inferior"
@@ -754,7 +773,7 @@ msgstr "Tanca la barra de navegació inferior"
msgid "Closes password update alert"
msgstr "Tanca l'alerta d'actualització de contrasenya"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "Tanca l'editor de la publicació i descarta l'esborrany"
@@ -787,7 +806,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "Crea publicacions de fins a {MAX_GRAPHEME_LENGTH} carĆ cters"
@@ -851,7 +870,7 @@ msgstr "Connectantā¦"
msgid "Contact support"
msgstr "Contacta amb suport"
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Filtre de contingut"
@@ -917,7 +936,7 @@ msgstr "Número de versió copiat en memòria"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "Copiat en memòria"
@@ -933,7 +952,7 @@ msgstr "Copia"
msgid "Copy link to list"
msgstr "Copia l'enllaƧ a la llista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Copia l'enllaç a la publicació"
@@ -941,7 +960,7 @@ msgstr "Copia l'enllaç a la publicació"
msgid "Copy link to profile"
msgstr "Copia l'enllaƧ al perfil"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "Copia el text de la publicació"
@@ -997,7 +1016,7 @@ msgstr "Creat per <0/>"
msgid "Created by you"
msgstr "Creat per tu"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "Crea una targeta amb una minuatura. La targeta enllaƧa a {url}"
@@ -1074,11 +1093,11 @@ msgstr "Elimina el meu compte"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Elimina la publicació"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "Vols eliminar aquesta publicació?"
@@ -1105,7 +1124,7 @@ msgstr "Descripció"
#~ msgid "Developer Tools"
#~ msgstr "Eines de desenvolupador"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "Vols dir alguna cosa?"
@@ -1113,15 +1132,15 @@ msgstr "Vols dir alguna cosa?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Descarta"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Descarta l'esborrany"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Evita que les aplicacions mostrin el meu compte als usuaris no connectats"
@@ -1200,7 +1219,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1272,6 +1291,7 @@ msgstr "Edita el perfil"
msgid "Edit Profile"
msgstr "Edita el perfil"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Edita els meus canals guardats"
@@ -1354,6 +1374,11 @@ msgstr "Fi del canal"
msgid "Enter a name for this App Password"
msgstr "Posa un nom a aquesta contrasenya d'aplicació"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "Entra el codi de confirmació"
@@ -1407,7 +1432,7 @@ msgstr "Introdueix el teu usuari i contrasenya"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Error:"
@@ -1478,7 +1503,7 @@ msgstr "No s'ha pogut crear la contrasenya d'aplicació"
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "No s'ha pogut crear la llista. Comprova la teva connexió a internet i torna-ho a provar."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "No s'ha pogut esborrar la publicació, torna-ho a provar"
@@ -1500,8 +1525,8 @@ msgid "Feed offline"
msgstr "Canal fora de lĆnia"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "PreferĆØncies del canal"
+#~ msgid "Feed Preferences"
+#~ msgstr "PreferĆØncies del canal"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1541,11 +1566,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr "Troba comptes per seguir"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Troba usuaris a Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Troba usuaris amb l'eina de cerca de la dreta"
@@ -1646,6 +1671,7 @@ msgid "Following {0}"
msgstr "Seguint {0}"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1685,7 +1711,7 @@ msgstr "He oblidat la contrasenya"
msgid "Forgot Password"
msgstr "He oblidat la contrasenya"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "De <0/>"
@@ -1718,7 +1744,7 @@ msgstr "Ves enrere"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr "VƩs a @{queryMaybeHandle}"
@@ -1735,6 +1761,10 @@ msgstr "Ves al següent"
msgid "Handle"
msgstr "Identificador"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr "Tens problemes?"
@@ -1773,7 +1803,7 @@ msgctxt "action"
msgid "Hide"
msgstr "Amaga"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Amaga l'entrada"
@@ -1782,7 +1812,7 @@ msgstr "Amaga l'entrada"
msgid "Hide the content"
msgstr "Amaga el contingut"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "Vols amagar aquesta entrada?"
@@ -1936,7 +1966,7 @@ msgstr "Introdueix la teva contrasenya"
msgid "Input your user handle"
msgstr "Introdueix el teu identificador d'usuari"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "Registre de publicació no và lid o no admès"
@@ -2038,7 +2068,7 @@ msgstr "Més informació"
msgid "Learn more about this warning"
msgstr "Més informació d'aquesta advertència"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Més informació sobre què és públic a Bluesky."
@@ -2118,7 +2148,7 @@ msgstr "li ha agradat la teva publicació"
msgid "Likes"
msgstr "M'agrades"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "M'agrades a aquesta publicació"
@@ -2175,7 +2205,7 @@ msgstr "Carrega mƩs publicacions"
msgid "Load new notifications"
msgstr "Carrega noves notificacions"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2201,7 +2231,7 @@ msgstr "Registre"
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "Visibilitat pels usuaris no connectats"
@@ -2216,6 +2246,10 @@ msgstr "Accedeix a un compte que no estĆ llistat"
msgid "Make sure this is where you intend to go!"
msgstr "Assegura't que és aquà on vols anar!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2237,7 +2271,7 @@ msgid "Mentioned users"
msgstr "Usuaris mencionats"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "MenĆŗ"
@@ -2250,7 +2284,7 @@ msgid "Message from server: {0}"
msgstr "Missatge del servidor: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2281,7 +2315,7 @@ msgstr "S'ha creat la llista de moderació"
msgid "Moderation list updated"
msgstr "S'ha actualitzat la llista de moderació"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Llistes de moderació"
@@ -2308,7 +2342,7 @@ msgstr "MƩs canals"
msgid "More options"
msgstr "MƩs opcions"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "Més opcions de publicació"
@@ -2320,6 +2354,14 @@ msgstr "Respostes amb mƩs m'agrada primer"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Silenciar el compte"
@@ -2328,6 +2370,18 @@ msgstr "Silenciar el compte"
msgid "Mute accounts"
msgstr "Silencia els comptes"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "Silencia la llista"
@@ -2340,15 +2394,27 @@ msgstr "Vols silenciar aquests comptes?"
msgid "Mute this List"
msgstr "Silencia aquesta llista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Silencia el fil de debat"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "Silenciada"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Comptes silenciats"
@@ -2361,6 +2427,10 @@ msgstr "Comptes silenciats"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "Les publicacions dels comptes silenciats seran eliminats del teu canal i de les teves notificacions. Silenciar comptes Ʃs completament privat."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Silenciar és privat. Els comptes silenciats poden interactuar amb tu, però tu no veuràs les seves publicacions ni rebràs notificacions seves."
@@ -2424,6 +2494,10 @@ msgstr "No perdis mai accƩs als teus seguidors ni a les teves dades."
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2445,7 +2519,7 @@ msgstr "Nova contrasenya"
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "Nova publicació"
@@ -2534,8 +2608,8 @@ msgid "No results found for \"{query}\""
msgstr "No s'han trobat resultats per \"{query}\""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "No s'han trobat resultats per {query}"
@@ -2561,7 +2635,7 @@ msgstr "No s'ha trobat"
msgid "Not right now"
msgstr "Ara mateix no"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Nota: Bluesky és una xarxa oberta i pública. Aquesta configuració tan sols limita el teu contingut a l'aplicació de Bluesky i a la web, altres aplicacions poden no respectar-ho. El teu contingut pot ser mostrat a usuaris no connectats per altres aplicacions i webs."
@@ -2599,7 +2673,7 @@ msgstr "Respostes mƩs antigues primer"
msgid "Onboarding reset"
msgstr "Restableix la incorporació"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "Falta el text alternatiu a una o mƩs imatges."
@@ -2616,8 +2690,12 @@ msgstr "Ostres!"
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "Obre el selector d'emojis"
@@ -2625,6 +2703,10 @@ msgstr "Obre el selector d'emojis"
msgid "Open links with in-app browser"
msgstr "Obre els enllaços al navegador de l'aplicació"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Obre la navegació"
@@ -2701,6 +2783,7 @@ msgstr "Obre la configuració de la moderació"
msgid "Opens password reset form"
msgstr "Obre el formulari de restabliment de la contrasenya"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "Obre pantalla per editar els canals desats"
@@ -2879,7 +2962,7 @@ msgstr "Digues-nos per quĆØ creus que s'ha aplicat incorrectament l'advertĆØncia
msgid "Please Verify Your Email"
msgstr "Verifica el teu correu"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "Espera que es generi la targeta de l'enllaƧ"
@@ -2891,8 +2974,8 @@ msgstr ""
msgid "Porn"
msgstr "Pornografia"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "Publica"
@@ -2908,7 +2991,7 @@ msgstr "Publicació"
#~ msgid "Post"
#~ msgstr "Publicació"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "Publicació per {0}"
@@ -2918,11 +3001,11 @@ msgstr "Publicació per {0}"
msgid "Post by @{0}"
msgstr "Publicació per @{0}"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "Publicació eliminada"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Publicació oculta"
@@ -2934,14 +3017,22 @@ msgstr "Idioma de la publicació"
msgid "Post Languages"
msgstr "Idiomes de les publicacions"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Publicació no trobada"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "Publicacions"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "Publicacions amagades"
@@ -3006,11 +3097,11 @@ msgstr "Llistes d'usuaris per silenciar o bloquejar en massa, pĆŗbliques i per c
msgid "Public, shareable lists which can drive feeds."
msgstr "Llistes que poden nodrir canals, pĆŗbliques i per compartir."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "Publica"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "Publica la resposta"
@@ -3048,6 +3139,7 @@ msgstr "Canals recomanats"
msgid "Recommended Users"
msgstr "Usuaris recomanats"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3085,6 +3177,10 @@ msgstr "Elimina la imatge"
msgid "Remove image preview"
msgstr "Elimina la visualització prèvia de la imatge"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "Elimina la republicació"
@@ -3119,7 +3215,7 @@ msgstr "Respostes"
msgid "Replies to this thread are disabled"
msgstr "Les respostes a aquest fil de debat estan deshabilitades"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "Respon"
@@ -3129,7 +3225,7 @@ msgid "Reply Filters"
msgstr "Filtres de resposta"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "Resposta a <0/>"
@@ -3151,7 +3247,7 @@ msgid "Report List"
msgstr "Informa de la llista"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Informa de la publicació"
@@ -3180,7 +3276,7 @@ msgstr "Republica o cita la publicació"
msgid "Reposted By"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
@@ -3188,7 +3284,7 @@ msgstr ""
#~ msgid "Reposted by {0})"
#~ msgstr "Republicada per {0}"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "Republicada per <0/>"
@@ -3196,7 +3292,7 @@ msgstr "Republicada per <0/>"
msgid "reposted your post"
msgstr "ha republicat la teva publicació"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "Republicacions d'aquesta publicació"
@@ -3347,9 +3443,9 @@ msgstr "DesplaƧa't cap a dalt"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3359,11 +3455,19 @@ msgstr "DesplaƧa't cap a dalt"
msgid "Search"
msgstr "Cerca"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr "Cerca per \"{query}\""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3374,6 +3478,22 @@ msgstr "Cerca usuaris"
msgid "Security Step Required"
msgstr "Es requereix un pas de seguretat"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "Consulta aquesta guia"
@@ -3583,7 +3703,7 @@ msgid "Share"
msgstr "Comparteix"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Comparteix"
@@ -3616,9 +3736,9 @@ msgstr "Mostra els incrustats de {0}"
msgid "Show follows similar to {0}"
msgstr "Mostra seguidors semblants a {0}"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "Mostra mƩs"
@@ -3786,7 +3906,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr "Alguna cosa ha fallat. Comprova el teu correu i torna-ho a provar."
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "La teva sessió ha caducat. Torna a inciar-la."
@@ -3844,7 +3964,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "Subscriure's a la llista"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "Usuaris suggerits per seguir"
@@ -3888,6 +4008,14 @@ msgstr "Sistema"
msgid "System log"
msgstr "Registres del sistema"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "Alt"
@@ -3911,6 +4039,10 @@ msgstr "Condicions"
msgid "Terms of Service"
msgstr "Condicions del servei"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3936,7 +4068,7 @@ msgstr "La polĆtica de drets d'autoria ha estat traslladada a <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "Ćs possible que la publicació s'hagi esborrat."
@@ -4113,7 +4245,7 @@ msgstr "Aquesta llista estĆ buida!"
msgid "This name is already in use"
msgstr "Aquest nom ja estĆ en Ćŗs"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Aquesta publicació ha estat esborrada."
@@ -4137,7 +4269,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Aquesta advertència només està disponible per publicacions amb contingut adjuntat."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Això amagarà aquesta publicació dels teus canals."
@@ -4154,6 +4290,10 @@ msgstr "Mode fils de debat"
msgid "Threads Preferences"
msgstr "PreferĆØncies dels fils de debat"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Commuta el menĆŗ desplegable"
@@ -4162,9 +4302,9 @@ msgstr "Commuta el menĆŗ desplegable"
msgid "Transformations"
msgstr "Transformacions"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Tradueix"
@@ -4233,15 +4373,24 @@ msgstr "No compleixes les condicions per crear un compte."
msgid "Unlike"
msgstr "DesfƩs el m'agrada"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "Deixa de silenciar"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "Deixa de silenciar el compte"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "Deixa de silenciar el fil de debat"
@@ -4438,6 +4587,10 @@ msgstr ""
msgid "We ran out of posts from your follows. Here's the latest from <0/>."
msgstr "Ja no hi ha més publicacions dels usuaris que segueixes. Aquà n'hi ha altres de <0/>."
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4466,7 +4619,11 @@ msgstr "Ens fa molta il·lusió que t'uneixis a nosaltres!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "Ho sentim, però no hem pogut resoldre aquesta llista. Si això continua, posa't en contacte amb el creador de la llista, @{handleOrDid}."
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Ens sap greu, però la teva cerca no s'ha pogut fer. Prova-ho d'aquà una estona."
@@ -4490,7 +4647,7 @@ msgstr "Quin problema hi ha amb {collectionName}?"
#~ msgstr "¿Qué sigue?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "QuĆØ hi ha de nou"
@@ -4511,11 +4668,11 @@ msgstr "Qui hi pot respondre"
msgid "Wide"
msgstr "Amplada"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "Escriu una publicació"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "Escriu la teva resposta"
@@ -4576,7 +4733,7 @@ msgstr "No tens cap canal desat!"
msgid "You don't have any saved feeds."
msgstr "No tens cap canal desat."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "Has bloquejat l'autor o has estat bloquejat per ell."
@@ -4616,6 +4773,10 @@ msgstr "Encara no has creat cap contrasenya d'aplicació. Pots fer-ho amb el bot
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "Encara no has silenciat cap compte. Per fer-ho, vés al seu perfil i selecciona \"Silencia compte\" en el menú del seu compte."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "Has de tenir 18 anys o mƩs per habilitar el contingut per a adults."
@@ -4624,11 +4785,11 @@ msgstr "Has de tenir 18 anys o mƩs per habilitar el contingut per a adults."
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "Ja no rebràs més notificacions d'aquest debat"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "Ara rebrĆ s notificacions d'aquest debat"
@@ -4718,11 +4879,15 @@ msgstr "El teu identificador complet serĆ <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "Els teus codis d'invitació no es mostren quan has iniciat sessió amb una contrasenya d'aplicació"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "S'ha publicat"
@@ -4737,7 +4902,7 @@ msgstr "Les teves publicacions, m'agrades i bloquejos són públics. Els comptes
msgid "Your profile"
msgstr "El teu perfil"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "S'ha publicat a teva resposta"
diff --git a/src/locale/locales/de/messages.po b/src/locale/locales/de/messages.po
index a4b0a8cb3c..1c41880336 100644
--- a/src/locale/locales/de/messages.po
+++ b/src/locale/locales/de/messages.po
@@ -76,7 +76,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Eine neue Version der App ist verfügbar. Bitte aktualisiere die App, um sie weiter nutzen zu können."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr ""
@@ -127,6 +127,7 @@ msgstr ""
msgid "Account unmuted"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -168,14 +169,22 @@ msgstr "Details hinzufügen"
msgid "Add details to report"
msgstr "Details zum Report hinzufügen"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Link-Karte hinzufügen"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Link-Karte hinzufügen:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "Füge den folgenden DNS-Eintrag zu deiner Domain hinzu:"
@@ -299,7 +308,7 @@ msgstr ""
msgid "App Passwords"
msgstr "App-Passwƶrter"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr ""
@@ -323,15 +332,16 @@ msgstr "Erscheinungsbild"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "Bist du sicher, dass du das App-Passwort \"{name}\" lƶschen mƶchtest?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "Bist du sicher, dass du diesen Entwurf verwerfen mƶchtest?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "Bist du sicher?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "Bist du sicher? Dies kann nicht rückgängig gemacht werden."
@@ -353,15 +363,15 @@ msgstr "Künstlerische oder nicht-erotische Nacktheit."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "Zurück"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr ""
@@ -409,7 +419,7 @@ msgstr ""
msgid "Blocked"
msgstr ""
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Blockierte Konten"
@@ -468,7 +478,7 @@ msgstr "Bluesky ist ƶffentlich."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky nutzt Einladungen, um eine gesündere Community aufzubauen. Wenn du niemanden kennst, der eine Einladung hat, kannst du dich auf die Warteliste setzen lassen und wir schicken dir bald eine zu."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky zeigt dein Profil und deine Beiträge nicht für abgemeldete Nutzer an. Andere Apps kommen dieser Aufforderung möglicherweise nicht nach."
@@ -520,8 +530,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Darf nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche enthalten. Muss mindestens 4 Zeichen lang sein, darf aber nicht lƤnger als 32 Zeichen sein."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -535,7 +545,7 @@ msgstr "Darf nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "Abbrechen"
@@ -686,7 +696,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Alle Speicherdaten lƶschen (danach neu starten)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Suchanfrage lƶschen"
@@ -694,6 +704,11 @@ msgstr "Suchanfrage lƶschen"
msgid "click here"
msgstr ""
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -724,11 +739,15 @@ msgstr "Bild schlieĆen"
msgid "Close image viewer"
msgstr ""
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr ""
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr ""
@@ -736,7 +755,7 @@ msgstr ""
msgid "Closes password update alert"
msgstr ""
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr ""
@@ -769,7 +788,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr ""
@@ -833,7 +852,7 @@ msgstr "Verbinden..."
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Inhaltsfilterung"
@@ -899,7 +918,7 @@ msgstr ""
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr ""
@@ -915,7 +934,7 @@ msgstr "Kopieren"
msgid "Copy link to list"
msgstr "Link zur Liste kopieren"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Link zum Beitrag kopieren"
@@ -923,7 +942,7 @@ msgstr "Link zum Beitrag kopieren"
msgid "Copy link to profile"
msgstr "Link zum Profil kopieren"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr ""
@@ -979,7 +998,7 @@ msgstr ""
msgid "Created by you"
msgstr ""
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr ""
@@ -1056,11 +1075,11 @@ msgstr "Mein Konto lƶschen"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Beitrag lƶschen"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "Diesen Beitrag lƶschen?"
@@ -1083,7 +1102,7 @@ msgstr "Beschreibung"
#~ msgid "Developer Tools"
#~ msgstr "Entwickler-Tools"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr ""
@@ -1091,15 +1110,15 @@ msgstr ""
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Verwerfen"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Entwurf verwerfen"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Apps daran hindern, abgemeldeten Nutzern mein Konto zu zeigen"
@@ -1178,7 +1197,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1250,6 +1269,7 @@ msgstr "Profil bearbeiten"
msgid "Edit Profile"
msgstr "Profil bearbeiten"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Gespeicherte Feeds bearbeiten"
@@ -1332,6 +1352,11 @@ msgstr "Ende des Feeds"
msgid "Enter a name for this App Password"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr ""
@@ -1381,7 +1406,7 @@ msgstr "Gib deinen Benutzernamen und dein Passwort ein"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Fehler:"
@@ -1452,7 +1477,7 @@ msgstr ""
msgid "Failed to create the list. Check your internet connection and try again."
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr ""
@@ -1474,8 +1499,8 @@ msgid "Feed offline"
msgstr "Feed offline"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "Feed-Einstellungen"
+#~ msgid "Feed Preferences"
+#~ msgstr "Feed-Einstellungen"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1523,11 +1548,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr ""
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Nutzer auf Bluesky finden"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Finde Nutzer mit der Suchfunktion auf der rechten Seite"
@@ -1624,6 +1649,7 @@ msgid "Following {0}"
msgstr ""
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1663,7 +1689,7 @@ msgstr "Passwort vergessen"
msgid "Forgot Password"
msgstr "Passwort vergessen"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr ""
@@ -1696,7 +1722,7 @@ msgstr "Gehe zurück"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1713,6 +1739,10 @@ msgstr "Gehe zum nƤchsten"
msgid "Handle"
msgstr "Handle"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1751,7 +1781,7 @@ msgctxt "action"
msgid "Hide"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Beitrag ausblenden"
@@ -1760,7 +1790,7 @@ msgstr "Beitrag ausblenden"
msgid "Hide the content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "Diesen Beitrag ausblenden?"
@@ -1909,7 +1939,7 @@ msgstr ""
msgid "Input your user handle"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr ""
@@ -2011,7 +2041,7 @@ msgstr "Mehr erfahren"
msgid "Learn more about this warning"
msgstr "Erfahre mehr über diese Warnung"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Erfahre mehr darüber, was auf Bluesky öffentlich ist."
@@ -2087,7 +2117,7 @@ msgstr ""
msgid "Likes"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr ""
@@ -2144,7 +2174,7 @@ msgstr "Mehr BeitrƤge laden"
msgid "Load new notifications"
msgstr "Neue Benachrichtigungen laden"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2170,7 +2200,7 @@ msgstr ""
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr ""
@@ -2182,6 +2212,10 @@ msgstr "Anmeldung bei einem Konto, das nicht aufgelistet ist"
msgid "Make sure this is where you intend to go!"
msgstr "Vergewissere dich, dass du auch wirklich dorthin gehen willst!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2203,7 +2237,7 @@ msgid "Mentioned users"
msgstr "ErwƤhnte Benutzer"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "Menü"
@@ -2212,7 +2246,7 @@ msgid "Message from server: {0}"
msgstr "Nachricht vom Server: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2243,7 +2277,7 @@ msgstr ""
msgid "Moderation list updated"
msgstr ""
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Moderationslisten"
@@ -2270,7 +2304,7 @@ msgstr "Mehr Feeds"
msgid "More options"
msgstr "Mehr Optionen"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr ""
@@ -2282,6 +2316,14 @@ msgstr ""
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Konto stummschalten"
@@ -2290,6 +2332,18 @@ msgstr "Konto stummschalten"
msgid "Mute accounts"
msgstr "Konten stummschalten"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr ""
@@ -2302,15 +2356,27 @@ msgstr "Diese Konten stummschalten?"
msgid "Mute this List"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Thread stummschalten"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr ""
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Stummgeschaltete Konten"
@@ -2323,6 +2389,10 @@ msgstr "Stummgeschaltete Konten"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "Bei stummgeschalteten Konten werden ihre BeitrƤge aus deinem Feed und deinen Benachrichtigungen entfernt. Stummschaltungen sind vƶllig privat."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Stummschaltung ist privat. Stummgeschaltete Konten kƶnnen mit dir interagieren, aber du siehst ihre BeitrƤge nicht und erhƤltst keine Benachrichtigungen von ihnen."
@@ -2386,6 +2456,10 @@ msgstr "Verliere nie den Zugriff auf deine Follower und Daten."
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2407,7 +2481,7 @@ msgstr ""
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr ""
@@ -2492,8 +2566,8 @@ msgid "No results found for \"{query}\""
msgstr "Keine Ergebnisse für \"{query}\" gefunden"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "Keine Ergebnisse für {query} gefunden"
@@ -2519,7 +2593,7 @@ msgstr ""
msgid "Not right now"
msgstr ""
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Hinweis: Bluesky ist ein offenes und ƶffentliches Netzwerk. Diese Einstellung schrƤnkt lediglich die Sichtbarkeit deiner Inhalte in der Bluesky-App und auf der Website ein. Andere Apps respektieren diese Einstellung mƶglicherweise nicht. Deine Inhalte werden abgemeldeten Nutzern mƶglicherweise weiterhin in anderen Apps und Websites angezeigt."
@@ -2557,7 +2631,7 @@ msgstr ""
msgid "Onboarding reset"
msgstr ""
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "Bei einem oder mehreren Bildern fehlt der Alt-Text."
@@ -2574,8 +2648,12 @@ msgstr ""
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr ""
@@ -2583,6 +2661,10 @@ msgstr ""
msgid "Open links with in-app browser"
msgstr ""
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Navigation ƶffnen"
@@ -2659,6 +2741,7 @@ msgstr "Ćffnet die Moderationseinstellungen"
msgid "Opens password reset form"
msgstr ""
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr ""
@@ -2834,7 +2917,7 @@ msgstr "Bitte teile uns mit, warum du denkst, dass diese Inhaltswarnung falsch a
msgid "Please Verify Your Email"
msgstr ""
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr ""
@@ -2846,8 +2929,8 @@ msgstr ""
msgid "Porn"
msgstr ""
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr ""
@@ -2857,7 +2940,7 @@ msgctxt "description"
msgid "Post"
msgstr "Beitrag"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr ""
@@ -2867,11 +2950,11 @@ msgstr ""
msgid "Post by @{0}"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Beitrag ausgeblendet"
@@ -2883,14 +2966,22 @@ msgstr "Beitragssprache"
msgid "Post Languages"
msgstr "Beitragssprachen"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Beitrag nicht gefunden"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "BeitrƤge"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr ""
@@ -2955,11 +3046,11 @@ msgstr "Ćffentliche, gemeinsam nutzbare Listen von Nutzern, die du stummschalte
msgid "Public, shareable lists which can drive feeds."
msgstr "Ćffentliche, gemeinsam nutzbare Listen, die Feeds steuern kƶnnen."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr ""
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr ""
@@ -2993,6 +3084,7 @@ msgstr "Empfohlene Feeds"
msgid "Recommended Users"
msgstr "Empfohlene Nutzer"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3030,6 +3122,10 @@ msgstr "Bild entfernen"
msgid "Remove image preview"
msgstr "Bildvorschau entfernen"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr ""
@@ -3064,7 +3160,7 @@ msgstr "Antworten"
msgid "Replies to this thread are disabled"
msgstr "Antworten auf diesen Thread sind deaktiviert"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr ""
@@ -3074,7 +3170,7 @@ msgid "Reply Filters"
msgstr "Antwortfilter"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr ""
@@ -3096,7 +3192,7 @@ msgid "Report List"
msgstr "Liste melden"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Beitrag melden"
@@ -3121,11 +3217,11 @@ msgstr ""
msgid "Reposted By"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr ""
@@ -3133,7 +3229,7 @@ msgstr ""
msgid "reposted your post"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr ""
@@ -3284,9 +3380,9 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3296,11 +3392,19 @@ msgstr ""
msgid "Search"
msgstr "Suche"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3311,6 +3415,22 @@ msgstr "Nach Nutzern suchen"
msgid "Security Step Required"
msgstr "Sicherheitsschritt erforderlich"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr ""
@@ -3520,7 +3640,7 @@ msgid "Share"
msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Teilen"
@@ -3553,9 +3673,9 @@ msgstr ""
msgid "Show follows similar to {0}"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr ""
@@ -3723,7 +3843,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr ""
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr ""
@@ -3781,7 +3901,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "Abonniere diese Liste"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "Vorgeschlagene Follower"
@@ -3825,6 +3945,14 @@ msgstr ""
msgid "System log"
msgstr "Systemprotokoll"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "GroĆ"
@@ -3848,6 +3976,10 @@ msgstr "Bedingungen"
msgid "Terms of Service"
msgstr "Nutzungsbedingungen"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3873,7 +4005,7 @@ msgstr ""
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "Mƶglicherweise wurde der Post gelƶscht."
@@ -4039,7 +4171,7 @@ msgstr ""
msgid "This name is already in use"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Dieser Beitrag wurde gelƶscht."
@@ -4063,7 +4195,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Diese Warnung ist nur für Beiträge mit angehängten Medien verfügbar."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Dadurch wird dieser Beitrag aus deinen Feeds ausgeblendet."
@@ -4080,6 +4216,10 @@ msgstr ""
msgid "Threads Preferences"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr ""
@@ -4088,9 +4228,9 @@ msgstr ""
msgid "Transformations"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Ćbersetzen"
@@ -4155,15 +4295,24 @@ msgstr "Leider erfüllst du nicht die Voraussetzungen, um einen Account zu erste
msgid "Unlike"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr ""
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr ""
@@ -4364,6 +4513,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4392,7 +4545,11 @@ msgstr "Wir freuen uns sehr, dass du dabei bist!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr ""
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Es tut uns leid, aber deine Suche konnte nicht abgeschlossen werden. Bitte versuche es in ein paar Minuten erneut."
@@ -4413,7 +4570,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr ""
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "Was gibt's?"
@@ -4434,11 +4591,11 @@ msgstr "Wer antworten kann"
msgid "Wide"
msgstr "Breit"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "Beitrag verfassen"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "Schreibe deine Antwort"
@@ -4503,7 +4660,7 @@ msgstr "Du hast keine gespeicherten Feeds!"
msgid "You don't have any saved feeds."
msgstr "Du hast keine gespeicherten Feeds."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "Du hast den Verfasser blockiert oder du wurdest vom Verfasser blockiert."
@@ -4543,6 +4700,10 @@ msgstr "Du hast noch keine App-Passwƶrter erstellt. Du kannst eines erstellen,
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr ""
@@ -4551,11 +4712,11 @@ msgstr ""
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr ""
@@ -4641,11 +4802,15 @@ msgstr ""
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "Deine Einladungscodes werden ausgeblendet, wenn du dich mit einem App-Passwort anmeldest"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr ""
@@ -4660,7 +4825,7 @@ msgstr "Deine BeitrƤge, Likes und Blockierungen sind ƶffentlich. Stummschaltun
msgid "Your profile"
msgstr "Dein Profil"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr ""
diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po
index b944990551..cc40e1f0ef 100644
--- a/src/locale/locales/en/messages.po
+++ b/src/locale/locales/en/messages.po
@@ -76,7 +76,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr ""
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr ""
@@ -127,6 +127,7 @@ msgstr ""
msgid "Account unmuted"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -168,14 +169,22 @@ msgstr ""
msgid "Add details to report"
msgstr ""
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr ""
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr ""
@@ -299,7 +308,7 @@ msgstr ""
msgid "App Passwords"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr ""
@@ -323,15 +332,16 @@ msgstr ""
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr ""
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr ""
@@ -353,15 +363,15 @@ msgstr ""
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr ""
@@ -409,7 +419,7 @@ msgstr ""
msgid "Blocked"
msgstr ""
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr ""
@@ -468,7 +478,7 @@ msgstr ""
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr ""
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr ""
@@ -520,8 +530,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr ""
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -535,7 +545,7 @@ msgstr ""
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr ""
@@ -686,7 +696,7 @@ msgid "Clear all storage data (restart after this)"
msgstr ""
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr ""
@@ -694,6 +704,11 @@ msgstr ""
msgid "click here"
msgstr ""
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -724,11 +739,15 @@ msgstr ""
msgid "Close image viewer"
msgstr ""
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr ""
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr ""
@@ -736,7 +755,7 @@ msgstr ""
msgid "Closes password update alert"
msgstr ""
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr ""
@@ -769,7 +788,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr ""
@@ -833,7 +852,7 @@ msgstr ""
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr ""
@@ -899,7 +918,7 @@ msgstr ""
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr ""
@@ -915,7 +934,7 @@ msgstr ""
msgid "Copy link to list"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr ""
@@ -923,7 +942,7 @@ msgstr ""
msgid "Copy link to profile"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr ""
@@ -979,7 +998,7 @@ msgstr ""
msgid "Created by you"
msgstr ""
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr ""
@@ -1056,11 +1075,11 @@ msgstr ""
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr ""
@@ -1083,7 +1102,7 @@ msgstr ""
#~ msgid "Developer Tools"
#~ msgstr ""
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr ""
@@ -1091,15 +1110,15 @@ msgstr ""
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr ""
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr ""
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr ""
@@ -1178,7 +1197,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1250,6 +1269,7 @@ msgstr ""
msgid "Edit Profile"
msgstr ""
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr ""
@@ -1332,6 +1352,11 @@ msgstr ""
msgid "Enter a name for this App Password"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr ""
@@ -1381,7 +1406,7 @@ msgstr ""
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr ""
@@ -1452,7 +1477,7 @@ msgstr ""
msgid "Failed to create the list. Check your internet connection and try again."
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr ""
@@ -1474,8 +1499,8 @@ msgid "Feed offline"
msgstr ""
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr ""
+#~ msgid "Feed Preferences"
+#~ msgstr ""
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1523,11 +1548,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr ""
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr ""
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr ""
@@ -1624,6 +1649,7 @@ msgid "Following {0}"
msgstr ""
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1663,7 +1689,7 @@ msgstr ""
msgid "Forgot Password"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr ""
@@ -1696,7 +1722,7 @@ msgstr ""
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1713,6 +1739,10 @@ msgstr ""
msgid "Handle"
msgstr ""
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1751,7 +1781,7 @@ msgctxt "action"
msgid "Hide"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr ""
@@ -1760,7 +1790,7 @@ msgstr ""
msgid "Hide the content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr ""
@@ -1909,7 +1939,7 @@ msgstr ""
msgid "Input your user handle"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr ""
@@ -2011,7 +2041,7 @@ msgstr ""
msgid "Learn more about this warning"
msgstr ""
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr ""
@@ -2087,7 +2117,7 @@ msgstr ""
msgid "Likes"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr ""
@@ -2144,7 +2174,7 @@ msgstr ""
msgid "Load new notifications"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2170,7 +2200,7 @@ msgstr ""
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr ""
@@ -2182,6 +2212,10 @@ msgstr ""
msgid "Make sure this is where you intend to go!"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2203,7 +2237,7 @@ msgid "Mentioned users"
msgstr ""
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr ""
@@ -2212,7 +2246,7 @@ msgid "Message from server: {0}"
msgstr ""
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2243,7 +2277,7 @@ msgstr ""
msgid "Moderation list updated"
msgstr ""
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr ""
@@ -2270,7 +2304,7 @@ msgstr ""
msgid "More options"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr ""
@@ -2282,6 +2316,14 @@ msgstr ""
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr ""
@@ -2290,6 +2332,18 @@ msgstr ""
msgid "Mute accounts"
msgstr ""
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr ""
@@ -2302,15 +2356,27 @@ msgstr ""
msgid "Mute this List"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr ""
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr ""
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr ""
@@ -2323,6 +2389,10 @@ msgstr ""
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr ""
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr ""
@@ -2386,6 +2456,10 @@ msgstr ""
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2407,7 +2481,7 @@ msgstr ""
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr ""
@@ -2492,8 +2566,8 @@ msgid "No results found for \"{query}\""
msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr ""
@@ -2519,7 +2593,7 @@ msgstr ""
msgid "Not right now"
msgstr ""
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr ""
@@ -2557,7 +2631,7 @@ msgstr ""
msgid "Onboarding reset"
msgstr ""
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr ""
@@ -2574,8 +2648,12 @@ msgstr ""
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr ""
@@ -2583,6 +2661,10 @@ msgstr ""
msgid "Open links with in-app browser"
msgstr ""
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr ""
@@ -2659,6 +2741,7 @@ msgstr ""
msgid "Opens password reset form"
msgstr ""
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr ""
@@ -2839,7 +2922,7 @@ msgstr ""
msgid "Please Verify Your Email"
msgstr ""
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr ""
@@ -2851,8 +2934,8 @@ msgstr ""
msgid "Porn"
msgstr ""
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr ""
@@ -2862,7 +2945,7 @@ msgctxt "description"
msgid "Post"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr ""
@@ -2872,11 +2955,11 @@ msgstr ""
msgid "Post by @{0}"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr ""
@@ -2888,14 +2971,22 @@ msgstr ""
msgid "Post Languages"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr ""
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr ""
@@ -2960,11 +3051,11 @@ msgstr ""
msgid "Public, shareable lists which can drive feeds."
msgstr ""
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr ""
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr ""
@@ -2998,6 +3089,7 @@ msgstr ""
msgid "Recommended Users"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3035,6 +3127,10 @@ msgstr ""
msgid "Remove image preview"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr ""
@@ -3069,7 +3165,7 @@ msgstr ""
msgid "Replies to this thread are disabled"
msgstr ""
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr ""
@@ -3079,7 +3175,7 @@ msgid "Reply Filters"
msgstr ""
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr ""
@@ -3101,7 +3197,7 @@ msgid "Report List"
msgstr ""
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr ""
@@ -3126,11 +3222,11 @@ msgstr ""
msgid "Reposted By"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr ""
@@ -3138,7 +3234,7 @@ msgstr ""
msgid "reposted your post"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr ""
@@ -3289,9 +3385,9 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3301,11 +3397,19 @@ msgstr ""
msgid "Search"
msgstr ""
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3316,6 +3420,22 @@ msgstr ""
msgid "Security Step Required"
msgstr ""
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr ""
@@ -3525,7 +3645,7 @@ msgid "Share"
msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr ""
@@ -3558,9 +3678,9 @@ msgstr ""
msgid "Show follows similar to {0}"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr ""
@@ -3728,7 +3848,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr ""
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr ""
@@ -3786,7 +3906,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr ""
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr ""
@@ -3830,6 +3950,14 @@ msgstr ""
msgid "System log"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr ""
@@ -3853,6 +3981,10 @@ msgstr ""
msgid "Terms of Service"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3878,7 +4010,7 @@ msgstr ""
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr ""
@@ -4044,7 +4176,7 @@ msgstr ""
msgid "This name is already in use"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr ""
@@ -4068,7 +4200,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr ""
@@ -4085,6 +4221,10 @@ msgstr ""
msgid "Threads Preferences"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr ""
@@ -4093,9 +4233,9 @@ msgstr ""
msgid "Transformations"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr ""
@@ -4160,15 +4300,24 @@ msgstr ""
msgid "Unlike"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr ""
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr ""
@@ -4369,6 +4518,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4397,7 +4550,11 @@ msgstr ""
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr ""
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr ""
@@ -4418,7 +4575,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr ""
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr ""
@@ -4439,11 +4596,11 @@ msgstr ""
msgid "Wide"
msgstr ""
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr ""
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr ""
@@ -4508,7 +4665,7 @@ msgstr ""
msgid "You don't have any saved feeds."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr ""
@@ -4548,6 +4705,10 @@ msgstr ""
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr ""
@@ -4556,11 +4717,11 @@ msgstr ""
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr ""
@@ -4646,11 +4807,15 @@ msgstr ""
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr ""
@@ -4665,7 +4830,7 @@ msgstr ""
msgid "Your profile"
msgstr ""
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr ""
diff --git a/src/locale/locales/es/messages.po b/src/locale/locales/es/messages.po
index b0689cb5a5..fed1beb6cb 100644
--- a/src/locale/locales/es/messages.po
+++ b/src/locale/locales/es/messages.po
@@ -76,7 +76,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Ya estĆ” disponible una nueva versión de la aplicación. ActualĆzala para seguir utilizĆ”ndola."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr ""
@@ -127,6 +127,7 @@ msgstr ""
msgid "Account unmuted"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -168,14 +169,22 @@ msgstr "Agregar detalles"
msgid "Add details to report"
msgstr "Agregar detalles al informe"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Agregar una tarjeta de enlace"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Agregar una tarjeta de enlace:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "AƱade el siguiente registro DNS a tu dominio:"
@@ -299,7 +308,7 @@ msgstr ""
msgid "App Passwords"
msgstr "ContraseƱas de la app"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "Aviso sobre el contenido del recurso"
@@ -323,15 +332,16 @@ msgstr "Aspecto exterior"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "¿EstÔs seguro de que quieres eliminar la contraseña de la app \"{name}\"?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "¿EstÔs seguro de que quieres descartar este borrador?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "¿EstÔs seguro?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "¿EstÔs seguro? Esto no puede deshacerse."
@@ -353,15 +363,15 @@ msgstr "Desnudez artĆstica o no erótica."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "Regresar"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr ""
@@ -409,7 +419,7 @@ msgstr ""
msgid "Blocked"
msgstr ""
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Cuentas bloqueadas"
@@ -468,7 +478,7 @@ msgstr "Bluesky es pĆŗblico."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky utiliza las invitaciones para construir una comunidad mÔs saludable. Si no conoces a nadie con una invitación, puedes apuntarte a la lista de espera y te enviaremos una en breve."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky no mostrarÔ tu perfil ni tus publicaciones a los usuarios que hayan cerrado sesión. Es posible que otras aplicaciones no acepten esta solicitud. Esto no hace que tu cuenta sea privada."
@@ -520,8 +530,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Sólo puede contener letras, números, espacios, guiones y guiones bajos. Debe tener al menos 4 caracteres, pero no mÔs de 32."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -535,7 +545,7 @@ msgstr "Sólo puede contener letras, números, espacios, guiones y guiones bajos
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "Cancelar"
@@ -686,7 +696,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Borrar todos los datos de almacenamiento (reiniciar despuƩs de esto)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Borrar consulta de bĆŗsqueda"
@@ -694,6 +704,11 @@ msgstr "Borrar consulta de bĆŗsqueda"
msgid "click here"
msgstr ""
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -724,11 +739,15 @@ msgstr "Cerrar la imagen"
msgid "Close image viewer"
msgstr "Cerrar el visor de imagen"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "Cerrar el pie de pÔgina de navegación"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr ""
@@ -736,7 +755,7 @@ msgstr ""
msgid "Closes password update alert"
msgstr ""
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr ""
@@ -769,7 +788,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr ""
@@ -833,7 +852,7 @@ msgstr "Conectando..."
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Filtro de contenido"
@@ -899,7 +918,7 @@ msgstr ""
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr ""
@@ -915,7 +934,7 @@ msgstr "Copiar"
msgid "Copy link to list"
msgstr "Copia el enlace a la lista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Copia el enlace a la publicación"
@@ -923,7 +942,7 @@ msgstr "Copia el enlace a la publicación"
msgid "Copy link to profile"
msgstr "Copia el enlace al perfil"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "Copiar el texto de la publicación"
@@ -979,7 +998,7 @@ msgstr ""
msgid "Created by you"
msgstr ""
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr ""
@@ -1056,11 +1075,11 @@ msgstr "Borrar mi cuenta"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Borrar una publicación"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "¿Borrar esta publicación?"
@@ -1083,7 +1102,7 @@ msgstr "Descripción"
#~ msgid "Developer Tools"
#~ msgstr "Herramientas de desarrollador"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "ĀæQuieres decir algo?"
@@ -1091,15 +1110,15 @@ msgstr "ĀæQuieres decir algo?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Descartar"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Descartar el borrador"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Evitar que las aplicaciones muestren mi cuenta a los usuarios desconectados"
@@ -1178,7 +1197,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1250,6 +1269,7 @@ msgstr "Editar el perfil"
msgid "Edit Profile"
msgstr "Editar el perfil"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Editar mis noticias guardadas"
@@ -1332,6 +1352,11 @@ msgstr "Fin de noticias"
msgid "Enter a name for this App Password"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr ""
@@ -1381,7 +1406,7 @@ msgstr "Introduce tu nombre de usuario y contraseƱa"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Error:"
@@ -1452,7 +1477,7 @@ msgstr ""
msgid "Failed to create the list. Check your internet connection and try again."
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr ""
@@ -1474,8 +1499,8 @@ msgid "Feed offline"
msgstr "Noticias fuera de lĆnea"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "Preferencias de noticias"
+#~ msgid "Feed Preferences"
+#~ msgstr "Preferencias de noticias"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1523,11 +1548,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr ""
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Encontrar usuarios en Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Encuentra usuarios con la herramienta de bĆŗsqueda de la derecha"
@@ -1624,6 +1649,7 @@ msgid "Following {0}"
msgstr ""
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1663,7 +1689,7 @@ msgstr "OlvidƩ mi contraseƱa"
msgid "Forgot Password"
msgstr "OlvidƩ mi contraseƱa"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr ""
@@ -1696,7 +1722,7 @@ msgstr "Regresar"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1713,6 +1739,10 @@ msgstr "Ir al siguiente"
msgid "Handle"
msgstr "Identificador"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1751,7 +1781,7 @@ msgctxt "action"
msgid "Hide"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Ocultar publicación"
@@ -1760,7 +1790,7 @@ msgstr "Ocultar publicación"
msgid "Hide the content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "¿Ocultar esta publicación?"
@@ -1909,7 +1939,7 @@ msgstr ""
msgid "Input your user handle"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr ""
@@ -2011,7 +2041,7 @@ msgstr "Aprender mƔs"
msgid "Learn more about this warning"
msgstr "Aprender mƔs acerca de esta advertencia"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "MÔs información sobre lo que es público en Bluesky."
@@ -2087,7 +2117,7 @@ msgstr ""
msgid "Likes"
msgstr "Cantidad de «Me gusta»"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr ""
@@ -2144,7 +2174,7 @@ msgstr "Cargar mƔs publicaciones"
msgid "Load new notifications"
msgstr "Cargar notificaciones nuevas"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2170,7 +2200,7 @@ msgstr ""
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "Visibilidad de desconexión"
@@ -2182,6 +2212,10 @@ msgstr "Acceder a una cuenta que no estĆ” en la lista"
msgid "Make sure this is where you intend to go!"
msgstr "”Asegúrate de que es aquà a donde pretendes ir!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2203,7 +2237,7 @@ msgid "Mentioned users"
msgstr "Usuarios mencionados"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "MenĆŗ"
@@ -2212,7 +2246,7 @@ msgid "Message from server: {0}"
msgstr "Mensaje del servidor: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2243,7 +2277,7 @@ msgstr ""
msgid "Moderation list updated"
msgstr ""
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Listas de moderación"
@@ -2270,7 +2304,7 @@ msgstr "MƔs canales de noticias"
msgid "More options"
msgstr "MƔs opciones"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr ""
@@ -2282,6 +2316,14 @@ msgstr ""
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Silenciar la cuenta"
@@ -2290,6 +2332,18 @@ msgstr "Silenciar la cuenta"
msgid "Mute accounts"
msgstr "Silenciar las cuentas"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "Silenciar la lista"
@@ -2302,15 +2356,27 @@ msgstr "ĀæSilenciar estas cuentas?"
msgid "Mute this List"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Silenciar el hilo"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr ""
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Cuentas silenciadas"
@@ -2323,6 +2389,10 @@ msgstr "Cuentas silenciadas"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "Las cuentas silenciadas eliminan sus publicaciones de tu canal de noticias y de tus notificaciones. Las cuentas silenciadas son completamente privadas."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Silenciar es privado. Las cuentas silenciadas pueden interactuar contigo, pero no verƔs sus publicaciones ni recibirƔs notificaciones suyas."
@@ -2386,6 +2456,10 @@ msgstr "No pierdas nunca el acceso a tus seguidores y datos."
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2407,7 +2481,7 @@ msgstr ""
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr ""
@@ -2492,8 +2566,8 @@ msgid "No results found for \"{query}\""
msgstr "No se han encontrado resultados para \"{query}\""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "No se han encontrado resultados para {query}"
@@ -2519,7 +2593,7 @@ msgstr ""
msgid "Not right now"
msgstr ""
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Nota: Bluesky es una red abierta y pública. Esta configuración sólo limita la visibilidad de tu contenido en la aplicación y el sitio web de Bluesky, y es posible que otras aplicaciones no respeten esta configuración. Otras aplicaciones y sitios web pueden seguir mostrando tu contenido a los usuarios que hayan cerrado sesión."
@@ -2557,7 +2631,7 @@ msgstr ""
msgid "Onboarding reset"
msgstr ""
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "Falta el texto alternativo en una o varias imƔgenes."
@@ -2574,8 +2648,12 @@ msgstr ""
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr ""
@@ -2583,6 +2661,10 @@ msgstr ""
msgid "Open links with in-app browser"
msgstr ""
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Abrir navegación"
@@ -2659,6 +2741,7 @@ msgstr "Abre la configuración de moderación"
msgid "Opens password reset form"
msgstr ""
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr ""
@@ -2834,7 +2917,7 @@ msgstr "Por favor, dinos por quƩ crees que esta advertencia de contenido se ha
msgid "Please Verify Your Email"
msgstr ""
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "Por favor, espera a que tu tarjeta de enlace termine de cargarse"
@@ -2846,8 +2929,8 @@ msgstr ""
msgid "Porn"
msgstr ""
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr ""
@@ -2857,7 +2940,7 @@ msgctxt "description"
msgid "Post"
msgstr "Publicación"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr ""
@@ -2867,11 +2950,11 @@ msgstr ""
msgid "Post by @{0}"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Publicación oculta"
@@ -2883,14 +2966,22 @@ msgstr "Lenguaje de la publicación"
msgid "Post Languages"
msgstr "Lenguajes de la publicación"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Publicación no encontrada"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "Publicaciones"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr ""
@@ -2955,11 +3046,11 @@ msgstr "Listas pĆŗblicas y compartibles de usuarios para silenciar o bloquear en
msgid "Public, shareable lists which can drive feeds."
msgstr "Listas pĆŗblicas y compartibles que pueden impulsar las noticias."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr ""
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr ""
@@ -2993,6 +3084,7 @@ msgstr "Canales de noticias recomendados"
msgid "Recommended Users"
msgstr "Usuarios recomendados"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3030,6 +3122,10 @@ msgstr "Eliminar la imagen"
msgid "Remove image preview"
msgstr "Eliminar la vista previa de la imagen"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr ""
@@ -3064,7 +3160,7 @@ msgstr "Respuestas"
msgid "Replies to this thread are disabled"
msgstr "Las respuestas a este hilo estƔn desactivadas"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr ""
@@ -3074,7 +3170,7 @@ msgid "Reply Filters"
msgstr "Filtros de respuestas"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr ""
@@ -3096,7 +3192,7 @@ msgid "Report List"
msgstr "Informe de la lista"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Informe de la publicación"
@@ -3121,11 +3217,11 @@ msgstr "Volver a publicar o citar publicación"
msgid "Reposted By"
msgstr "Vuelto a publicar por"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr "Vuelto a publicar por {0}"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "Vuelto a publicar por <0/>"
@@ -3133,7 +3229,7 @@ msgstr "Vuelto a publicar por <0/>"
msgid "reposted your post"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr ""
@@ -3284,9 +3380,9 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3296,11 +3392,19 @@ msgstr ""
msgid "Search"
msgstr "Buscar"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3311,6 +3415,22 @@ msgstr "Buscar usuarios"
msgid "Security Step Required"
msgstr "Se requiere un paso de seguridad"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr ""
@@ -3520,7 +3640,7 @@ msgid "Share"
msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Compartir"
@@ -3553,9 +3673,9 @@ msgstr ""
msgid "Show follows similar to {0}"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr ""
@@ -3723,7 +3843,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr ""
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr ""
@@ -3781,7 +3901,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "Suscribirse a esta lista"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "Usuarios sugeridos a seguir"
@@ -3825,6 +3945,14 @@ msgstr ""
msgid "System log"
msgstr "BitƔcora del sistema"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "Alto"
@@ -3848,6 +3976,10 @@ msgstr "Condiciones"
msgid "Terms of Service"
msgstr "Condiciones de servicio"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3873,7 +4005,7 @@ msgstr "La PolĆtica de derechos de autor se han trasladado a <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "Es posible que se haya borrado la publicación."
@@ -4039,7 +4171,7 @@ msgstr ""
msgid "This name is already in use"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Esta publicación ha sido eliminada."
@@ -4063,7 +4195,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Esta advertencia sólo estÔ disponible para las publicaciones con medios adjuntos."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Esto ocultarĆ” esta entrada de tus contenidos."
@@ -4080,6 +4216,10 @@ msgstr "Modo con hilos"
msgid "Threads Preferences"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Conmutar el menĆŗ desplegable"
@@ -4088,9 +4228,9 @@ msgstr "Conmutar el menĆŗ desplegable"
msgid "Transformations"
msgstr "Transformaciones"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Traducir"
@@ -4155,15 +4295,24 @@ msgstr "Lamentablemente, no cumples los requisitos para crear una cuenta."
msgid "Unlike"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr ""
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "Desactivar la opción de silenciar la cuenta"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "Desactivar la opción de silenciar el hilo"
@@ -4364,6 +4513,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4392,7 +4545,11 @@ msgstr "”Nos hace mucha ilusión que te unas a nosotros!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr ""
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Lo sentimos, pero no se ha podido completar tu bĆŗsqueda. Vuelve a intentarlo dentro de unos minutos."
@@ -4413,7 +4570,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "¿CuÔl es el problema con esta {collectionName}?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "¿Qué hay de nuevo?"
@@ -4434,11 +4591,11 @@ msgstr "QuiƩn puede responder"
msgid "Wide"
msgstr "Ancho"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "Redactar una publicación"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "Redactar tu respuesta"
@@ -4503,7 +4660,7 @@ msgstr "”No tienes ninguna noticia guardada!"
msgid "You don't have any saved feeds."
msgstr "No tienes ninguna noticia guardada."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "Has bloqueado al autor o has sido bloqueado por el autor."
@@ -4543,6 +4700,10 @@ msgstr "Aún no has creado ninguna contraseña de aplicación. Puedes crear una
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "AĆŗn no has silenciado ninguna cuenta. Para silenciar una cuenta, ve a su perfil y selecciona \"Silenciar cuenta\" en el menĆŗ de su cuenta."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr ""
@@ -4551,11 +4712,11 @@ msgstr ""
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr ""
@@ -4641,11 +4802,15 @@ msgstr ""
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "Tus códigos de invitación estÔn ocultos cuando inicias sesión con una contraseña de la app"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr ""
@@ -4660,7 +4825,7 @@ msgstr "Tus publicaciones, Me gustas y bloqueos son pĆŗblicos. Las cuentas silen
msgid "Your profile"
msgstr "Tu perfil"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr ""
diff --git a/src/locale/locales/fr/messages.po b/src/locale/locales/fr/messages.po
index 8a78424e22..44b9fb9a2b 100644
--- a/src/locale/locales/fr/messages.po
+++ b/src/locale/locales/fr/messages.po
@@ -80,7 +80,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Une nouvelle version de lāapplication est disponible. Veuillez faire la mise Ć jour pour continuer Ć utiliser lāapplication."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "AccĆØde aux liens de navigation et aux paramĆØtres"
@@ -131,6 +131,7 @@ msgstr "Compte dƩbloquƩ"
msgid "Account unmuted"
msgstr "Compte dƩmasquƩ"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -172,14 +173,22 @@ msgstr "Ajouter des dƩtails"
msgid "Add details to report"
msgstr "Ajouter des dƩtails au rapport"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Ajouter une carte de lien"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Ajouter une carte de lien :"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "Ajoutez lāenregistrement DNS suivant Ć votre domaine :"
@@ -303,7 +312,7 @@ msgstr "ParamĆØtres de mot de passe dāapplication"
msgid "App Passwords"
msgstr "Mots de passe dāapplication"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "Faire appel de lāavertissement sur le contenu"
@@ -327,15 +336,16 @@ msgstr "Affichage"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "Ćtes-vous sĆ»r de vouloir supprimer le mot de passe de lāapplication Ā« {name} Ā» ?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "Ćtes-vous sĆ»r de vouloir rejeter ce brouillon ?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "Vous confirmez ?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "Vous confirmez ? Cela ne pourra pas être annulé."
@@ -357,15 +367,15 @@ msgstr "NuditƩ artistique ou non Ʃrotique."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "ArriĆØre"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "Retour"
@@ -413,7 +423,7 @@ msgstr "Bloquer cette liste"
msgid "Blocked"
msgstr "BloquƩ"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Comptes bloquƩs"
@@ -472,7 +482,7 @@ msgstr "Bluesky est public."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky distribue des invitations pour construire une communautĆ© plus saine. Si personne ne peut vous donner une invitation, vous pouvez vous inscrire sur notre liste dāattente et nous vous en enverrons une bientĆ“t."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky nāaffichera pas votre profil et vos messages Ć des personnes non connectĆ©es. Il est possible que dāautres applications nāhonorent pas cette demande. Cela ne privatise pas votre compte."
@@ -524,8 +534,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Ne peut contenir que des lettres, des chiffres, des espaces, des tirets et des tirets bas. La longueur doit ĆŖtre dāau moins 4 caractĆØres, mais pas plus de 32."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -539,7 +549,7 @@ msgstr "Ne peut contenir que des lettres, des chiffres, des espaces, des tirets
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "Annuler"
@@ -690,7 +700,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Effacer toutes les donnƩes de stockage (redƩmarrer ensuite)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Effacer la recherche"
@@ -698,6 +708,11 @@ msgstr "Effacer la recherche"
msgid "click here"
msgstr "cliquez ici"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -728,11 +743,15 @@ msgstr "Fermer lāimage"
msgid "Close image viewer"
msgstr "Fermer la visionneuse dāimages"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "Fermer le pied de page de navigation"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "Ferme la barre de navigation du bas"
@@ -740,7 +759,7 @@ msgstr "Ferme la barre de navigation du bas"
msgid "Closes password update alert"
msgstr "Ferme la notification de mise Ć jour du mot de passe"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "Ferme la fenêtre de rédaction et supprime le brouillon"
@@ -773,7 +792,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "Permet dāĆ©crire des messages de {MAX_GRAPHEME_LENGTH} caractĆØres maximum"
@@ -837,7 +856,7 @@ msgstr "Connexionā¦"
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Filtrage du contenu"
@@ -903,7 +922,7 @@ msgstr "Version de build copiƩe dans le presse-papier"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "CopiƩ dans le presse-papier"
@@ -919,7 +938,7 @@ msgstr "Copie"
msgid "Copy link to list"
msgstr "Copier le lien vers la liste"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Copier le lien vers le post"
@@ -927,7 +946,7 @@ msgstr "Copier le lien vers le post"
msgid "Copy link to profile"
msgstr "Copier le lien vers le profil"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "Copier le texte du post"
@@ -983,7 +1002,7 @@ msgstr "CrƩƩe par <0/>"
msgid "Created by you"
msgstr "CrƩƩe par vous"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "CrƩe une carte avec une miniature. La carte pointe vers {url}"
@@ -1060,11 +1079,11 @@ msgstr "Supprimer mon compte"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Supprimer le post"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "Supprimer ce post ?"
@@ -1087,7 +1106,7 @@ msgstr "Description"
#~ msgid "Developer Tools"
#~ msgstr "Outils de dƩv"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "Vous vouliez dire quelque chose ?"
@@ -1095,15 +1114,15 @@ msgstr "Vous vouliez dire quelque chose ?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Ignorer"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Ignorer le brouillon"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Empêcher les applis de montrer mon compte aux personnes non connectées"
@@ -1182,7 +1201,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1254,6 +1273,7 @@ msgstr "Modifier le profil"
msgid "Edit Profile"
msgstr "Modifier le profil"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Modifier les fils dāactu enregistrĆ©s"
@@ -1336,6 +1356,11 @@ msgstr "Fin du fil dāactu"
msgid "Enter a name for this App Password"
msgstr "Entrer un nom pour ce mot de passe dāapplication"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "Entrer un code de confirmation"
@@ -1385,7 +1410,7 @@ msgstr "Entrez votre pseudo et votre mot de passe"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Erreur :"
@@ -1456,7 +1481,7 @@ msgstr "Ćchec de la crĆ©ation du mot de passe dāapplication."
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "Ćchec de la crĆ©ation de la liste. VĆ©rifiez votre connexion Internet et rĆ©essayez."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "Ćchec de la suppression du post, veuillez rĆ©essayer"
@@ -1478,8 +1503,8 @@ msgid "Feed offline"
msgstr "Fil dāactu hors ligne"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "PrĆ©fĆ©rences en matiĆØre de fil dāactu"
+#~ msgid "Feed Preferences"
+#~ msgstr "PrĆ©fĆ©rences en matiĆØre de fil dāactu"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1527,11 +1552,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr "Trouver des comptes Ć suivre"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Trouver des comptes sur Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Trouvez des comptes Ć lāaide de lāoutil de recherche, Ć droite"
@@ -1628,6 +1653,7 @@ msgid "Following {0}"
msgstr "Suit {0}"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1667,7 +1693,7 @@ msgstr "Mot de passe oubliƩ"
msgid "Forgot Password"
msgstr "Mot de passe oubliƩ"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "TirƩ de <0/>"
@@ -1700,7 +1726,7 @@ msgstr "Retour"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1717,6 +1743,10 @@ msgstr "Aller Ć la suite"
msgid "Handle"
msgstr "Pseudo"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1755,7 +1785,7 @@ msgctxt "action"
msgid "Hide"
msgstr "Cacher"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Cacher ce post"
@@ -1764,7 +1794,7 @@ msgstr "Cacher ce post"
msgid "Hide the content"
msgstr "Cacher ce contenu"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "Cacher ce post ?"
@@ -1913,7 +1943,7 @@ msgstr "Entrez votre mot de passe"
msgid "Input your user handle"
msgstr "Entrez votre pseudo"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "Enregistrement de post invalide ou non pris en charge"
@@ -2015,7 +2045,7 @@ msgstr "En savoir plus"
msgid "Learn more about this warning"
msgstr "En savoir plus sur cet avertissement"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "En savoir plus sur ce qui est public sur Bluesky."
@@ -2091,7 +2121,7 @@ msgstr "likƩ votre post"
msgid "Likes"
msgstr "Likes"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "Likes sur ce post"
@@ -2148,7 +2178,7 @@ msgstr "Charger plus dāarticles"
msgid "Load new notifications"
msgstr "Charger les nouvelles notifications"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2174,7 +2204,7 @@ msgstr "Journaux"
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "VisibilitƩ dƩconnectƩe"
@@ -2186,6 +2216,10 @@ msgstr "Se connecter Ć un compte qui nāest pas listĆ©"
msgid "Make sure this is where you intend to go!"
msgstr "Assurez-vous que cāest bien lĆ que vous avez lāintention dāaller !"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2207,7 +2241,7 @@ msgid "Mentioned users"
msgstr "Comptes mentionnƩs"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "Menu"
@@ -2216,7 +2250,7 @@ msgid "Message from server: {0}"
msgstr "Message du serveur : {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2247,7 +2281,7 @@ msgstr "Liste de modƩration crƩƩe"
msgid "Moderation list updated"
msgstr "Liste de modération mise à jour"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Listes de modƩration"
@@ -2274,7 +2308,7 @@ msgstr "Plus de fils dāactu"
msgid "More options"
msgstr "Plus dāoptions"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "Plus dāoptions de post"
@@ -2286,6 +2320,14 @@ msgstr "RƩponses les plus likƩes en premier"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Masquer le compte"
@@ -2294,6 +2336,18 @@ msgstr "Masquer le compte"
msgid "Mute accounts"
msgstr "Masquer les comptes"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "Masquer la liste"
@@ -2306,15 +2360,27 @@ msgstr "Masquer ces comptes ?"
msgid "Mute this List"
msgstr "Masquer cette liste"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Masquer ce fil de discussion"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr ""
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Comptes masquƩs"
@@ -2327,6 +2393,10 @@ msgstr "Comptes masquƩs"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "Les comptes masquĆ©s voient leurs posts supprimĆ©s de votre fil dāactualitĆ© et de vos notifications. Cette option est totalement privĆ©e."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Ce que vous masquez reste privƩ. Les comptes masquƩs peuvent interagir avec vous, mais vous ne verrez pas leurs posts et ne recevrez pas de notifications de leur part."
@@ -2390,6 +2460,10 @@ msgstr "Ne perdez jamais lāaccĆØs Ć vos followers et Ć vos donnĆ©es."
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2411,7 +2485,7 @@ msgstr "Nouveau mot de passe"
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "Nouveau post"
@@ -2496,8 +2570,8 @@ msgid "No results found for \"{query}\""
msgstr "Aucun résultat trouvé pour « {query} »"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "Aucun rƩsultat trouvƩ pour {query}"
@@ -2523,7 +2597,7 @@ msgstr "Introuvable"
msgid "Not right now"
msgstr "Pas maintenant"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Remarque : Bluesky est un rĆ©seau ouvert et public. Ce paramĆØtre limite uniquement la visibilitĆ© de votre contenu sur lāapplication et le site Web de Bluesky, et dāautres applications peuvent ne pas respecter ce paramĆØtre. Votre contenu peut toujours ĆŖtre montrĆ© aux personnes non connectĆ©es par dāautres applications et sites Web."
@@ -2561,7 +2635,7 @@ msgstr "Plus anciennes rƩponses en premier"
msgid "Onboarding reset"
msgstr "RƩinitialiser le didacticiel"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "Une ou plusieurs images nāont pas de texte alt."
@@ -2578,8 +2652,12 @@ msgstr "Oups !"
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "Ouvrir le sĆ©lecteur dāemoji"
@@ -2587,6 +2665,10 @@ msgstr "Ouvrir le sĆ©lecteur dāemoji"
msgid "Open links with in-app browser"
msgstr ""
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Navigation ouverte"
@@ -2663,6 +2745,7 @@ msgstr "Ouvre les paramètres de modération"
msgid "Opens password reset form"
msgstr "Ouvre le formulaire de rƩinitialisation du mot de passe"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "Ouvre lāĆ©cran pour modifier les fils dāactu enregistrĆ©s"
@@ -2838,7 +2921,7 @@ msgstr "Dites-nous donc pourquoi vous pensez que cet avertissement de contenu a
msgid "Please Verify Your Email"
msgstr "Veuillez vƩrifier votre e-mail"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "Veuillez patienter le temps que votre carte de lien soit chargƩe"
@@ -2850,8 +2933,8 @@ msgstr ""
msgid "Porn"
msgstr "Porno"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "Poster"
@@ -2861,7 +2944,7 @@ msgctxt "description"
msgid "Post"
msgstr "Post"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "Post de {0}"
@@ -2871,11 +2954,11 @@ msgstr "Post de {0}"
msgid "Post by @{0}"
msgstr "Post de @{0}"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "Post supprimƩ"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Post cachƩ"
@@ -2887,14 +2970,22 @@ msgstr "Langue du post"
msgid "Post Languages"
msgstr "Langues du post"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Post introuvable"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "Posts"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "Posts cachƩs"
@@ -2959,11 +3050,11 @@ msgstr "Listes publiques et partageables de comptes Ć masquer ou Ć bloquer."
msgid "Public, shareable lists which can drive feeds."
msgstr "Les listes publiques et partageables qui peuvent alimenter les fils dāactu."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "Publier le post"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "Publier la rƩponse"
@@ -2997,6 +3088,7 @@ msgstr "Fils dāactu recommandĆ©s"
msgid "Recommended Users"
msgstr "Comptes recommandƩs"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3034,6 +3126,10 @@ msgstr "Supprimer lāimage"
msgid "Remove image preview"
msgstr "Supprimer lāaperƧu dāimage"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "Supprimer le repost"
@@ -3068,7 +3164,7 @@ msgstr "RƩponses"
msgid "Replies to this thread are disabled"
msgstr "Les réponses à ce fil de discussion sont désactivées"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "RƩpondre"
@@ -3078,7 +3174,7 @@ msgid "Reply Filters"
msgstr "Filtres de rƩponse"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "Réponse à <0/>"
@@ -3100,7 +3196,7 @@ msgid "Report List"
msgstr "Signaler la liste"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Signaler le post"
@@ -3125,11 +3221,11 @@ msgstr "Republier ou citer"
msgid "Reposted By"
msgstr "RepubliƩ par"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr "RepubliƩ par {0}"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "RepubliƩ par <0/>"
@@ -3137,7 +3233,7 @@ msgstr "RepubliƩ par <0/>"
msgid "reposted your post"
msgstr "a republiƩ votre post"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "Reposts de ce post"
@@ -3288,9 +3384,9 @@ msgstr "Remonter en haut"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3300,11 +3396,19 @@ msgstr "Remonter en haut"
msgid "Search"
msgstr "Recherche"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3315,6 +3419,22 @@ msgstr "Rechercher des comptes"
msgid "Security Step Required"
msgstr "Ćtape de sĆ©curitĆ© requise"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "Voir ce guide"
@@ -3524,7 +3644,7 @@ msgid "Share"
msgstr "Partager"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Partager"
@@ -3557,9 +3677,9 @@ msgstr "Afficher les intƩgrations de {0}"
msgid "Show follows similar to {0}"
msgstr "Afficher les suivis similaires Ć {0}"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "Voir plus"
@@ -3727,7 +3847,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr "Quelque chose nāa pas marchĆ©. VĆ©rifiez vos e-mails et rĆ©essayez."
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "DƩsolƩ ! Votre session a expirƩ. Essayez de vous reconnecter."
@@ -3785,7 +3905,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "Sāabonner Ć cette liste"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "Suivis suggƩrƩs"
@@ -3829,6 +3949,14 @@ msgstr "SystĆØme"
msgid "System log"
msgstr "Journal systĆØme"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "Grand"
@@ -3852,6 +3980,10 @@ msgstr "Conditions gƩnƩrales"
msgid "Terms of Service"
msgstr "Conditions dāutilisation"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3877,7 +4009,7 @@ msgstr "Notre politique de droits dāauteur a Ć©tĆ© dĆ©placĆ©e vers <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "Ce post a peut-être été supprimé."
@@ -4043,7 +4175,7 @@ msgstr "Cette liste est vide !"
msgid "This name is already in use"
msgstr "Ce nom est déjà utilisé"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Ce post a ƩtƩ supprimƩ."
@@ -4067,7 +4199,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Cet avertissement nāest disponible que pour les messages contenant des mĆ©dias."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Cela va masquer ce post de vos fils dāactu."
@@ -4084,6 +4220,10 @@ msgstr "Mode arborescent"
msgid "Threads Preferences"
msgstr "PrƩfƩrences de fils de discussion"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Activer le menu dƩroulant"
@@ -4092,9 +4232,9 @@ msgstr "Activer le menu dƩroulant"
msgid "Transformations"
msgstr "Transformations"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Traduire"
@@ -4159,15 +4299,24 @@ msgstr "Malheureusement, vous ne remplissez pas les conditions requises pour cr
msgid "Unlike"
msgstr "DƩliker"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "RƩafficher"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "RƩafficher ce compte"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "RƩafficher ce fil de discussion"
@@ -4368,6 +4517,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4396,7 +4549,11 @@ msgstr "Nous sommes ravis de vous accueillir !"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "Nous sommes dĆ©solĆ©s, mais nous nāavons pas pu charger cette liste. Si cela persiste, veuillez contacter lāorigine de la liste, @{handleOrDid}."
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Nous sommes dƩsolƩs, mais votre recherche a ƩtƩ annulƩe. Veuillez rƩessayer dans quelques minutes."
@@ -4417,7 +4574,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "Quel est le problĆØme avec cette {collectionName} ?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "Quoi de neuf ?"
@@ -4438,11 +4595,11 @@ msgstr "Qui peut rƩpondre ?"
msgid "Wide"
msgstr "Large"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "RƩdiger un post"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "RƩdigez votre rƩponse"
@@ -4507,7 +4664,7 @@ msgstr "Vous nāavez encore aucun fil enregistrĆ© !"
msgid "You don't have any saved feeds."
msgstr "Vous nāavez encore aucun fil enregistrĆ©."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "Vous avez bloquƩ cet auteur ou vous avez ƩtƩ bloquƩ par celui-ci."
@@ -4547,6 +4704,10 @@ msgstr "Vous nāavez encore crƩƩ aucun mot de passe pour lāappli. Vous pouv
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "Vous nāavez encore masquĆ© aucun compte. Pour dĆ©sactiver un compte, allez sur son profil et sĆ©lectionnez Ā« Masquer le compte Ā» dans le menu de son compte."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "Vous devez avoir 18 ans ou plus pour activer le contenu pour adultes."
@@ -4555,11 +4716,11 @@ msgstr "Vous devez avoir 18 ans ou plus pour activer le contenu pour adultes."
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "Vous ne recevrez plus de notifications pour ce fil de discussion"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "Vous recevrez dƩsormais des notifications pour ce fil de discussion"
@@ -4645,11 +4806,15 @@ msgstr "Votre pseudo complet sera <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "Vos codes dāinvitation sont cachĆ©s lorsque vous ĆŖtes connectĆ© Ć lāaide dāun mot de passe dāapplication."
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "Votre post a ƩtƩ publiƩ"
@@ -4664,7 +4829,7 @@ msgstr "Vos posts, les likes et les blocages sont publics. Les silences (comptes
msgid "Your profile"
msgstr "Votre profil"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "Votre rƩponse a ƩtƩ publiƩe"
diff --git a/src/locale/locales/hi/messages.po b/src/locale/locales/hi/messages.po
index 53bcdbe350..7d852d0b5a 100644
--- a/src/locale/locales/hi/messages.po
+++ b/src/locale/locales/hi/messages.po
@@ -80,7 +80,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "ą¤ą¤Ŗ ą¤ą¤¾ ą¤ą¤ नया ą¤øą¤ą¤øą„ą¤ą¤°ą¤£ ą¤ą¤Ŗą¤²ą¤¬ą„ध हą„. ą¤ą„पया ą¤ą¤Ŗ ą¤ą¤¾ ą¤ą¤Ŗą¤Æą„ą¤ ą¤ą¤¾ą¤°ą„ ą¤°ą¤ą¤Øą„ ą¤ą„ लिठą¤
ą¤Ŗą¤”ą„ą¤ ą¤ą¤°ą„ą¤ą„¤"
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr ""
@@ -131,6 +131,7 @@ msgstr ""
msgid "Account unmuted"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -172,14 +173,22 @@ msgstr "विवरण ą¤ą„ą¤”ą¤¼ą„ą¤"
msgid "Add details to report"
msgstr "ą¤°ą¤æą¤Ŗą„ą¤°ą„ą¤ ą¤ą¤°ą¤Øą„ ą¤ą„ लिठविवरण ą¤ą„ą¤”ą¤¼ą„ą¤"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "ą¤²ą¤æą¤ą¤ ą¤ą¤¾ą¤°ą„औ ą¤ą„ą¤”ą¤¼ą„ą¤"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "ą¤²ą¤æą¤ą¤ ą¤ą¤¾ą¤°ą„औ ą¤ą„ą¤”ą¤¼ą„ą¤:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "ą¤
ą¤Ŗą¤Øą„ ą¤”ą„ą¤®ą„न ą¤®ą„ą¤ ą¤Øą¤æą¤®ą„ą¤Øą¤²ą¤æą¤ą¤æą¤¤ DNS ą¤°ą¤æą¤ą„ą¤°ą„ą¤” ą¤ą„ą¤”ą¤¼ą„ą¤:"
@@ -303,7 +312,7 @@ msgstr ""
msgid "App Passwords"
msgstr "ą¤ą¤Ŗ ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤”"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr ""
@@ -327,15 +336,16 @@ msgstr "ą¤¦ą¤æą¤ą¤¾ą¤µą¤"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "ą¤ą„या ą¤ą¤Ŗ ą¤µą¤¾ą¤ą¤ ą¤ą¤Ŗ ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤” \"{name}\" ą¤¹ą¤ą¤¾ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą¤¤ą„ ą¤¹ą„ą¤?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "ą¤ą„या ą¤ą¤Ŗ ą¤µą¤¾ą¤ą¤ ą¤ą¤ø ą¤”ą„ą¤°ą¤¾ą¤«ą„ą¤ ą¤ą„ ą¤¹ą¤ą¤¾ą¤Øą¤¾ ą¤ą¤°ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą„ą¤ą¤ą„?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "ą¤ą„या ą¤ą¤Ŗ ą¤µą¤¾ą¤øą„ą¤¤ą¤µ ą¤®ą„ą¤ ą¤ą¤øą„ ą¤ą¤°ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą¤¤ą„ ą¤¹ą„ą¤?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "ą¤ą„या ą¤ą¤Ŗ ą¤µą¤¾ą¤øą„ą¤¤ą¤µ ą¤®ą„ą¤ ą¤ą¤øą„ ą¤ą¤°ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą¤¤ą„ ą¤¹ą„ą¤? ą¤ą¤øą„ ą¤
ą¤øą¤ą¤Ŗą¤¾ą¤¦ą¤æą¤¤ ą¤Øą¤¹ą„ą¤ ą¤ą¤æą¤Æą¤¾ ą¤ą¤¾ ą¤øą¤ą¤¤ą¤¾ ą¤¹ą„ą„¤"
@@ -357,15 +367,15 @@ msgstr "ą¤ą¤²ą¤¾ą¤¤ą„मठया ą¤ą„र-ą¤ą¤¾ą¤®ą„ą¤ ą¤Øą¤ą„नत
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "वापस"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr ""
@@ -413,7 +423,7 @@ msgstr ""
msgid "Blocked"
msgstr ""
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "ą¤¬ą„ą¤²ą„ą¤ ą¤ą¤æą¤ ą¤ą¤ ą¤ą¤¾ą¤¤ą„"
@@ -472,7 +482,7 @@ msgstr "Bluesky ą¤øą¤¾ą¤°ą„ą¤µą¤ą¤Øą¤æą¤ ą¤¹ą„ą„¤ą„¤"
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "ą¤¬ą„ą¤²ą„ą¤øą„ą¤ą„ ą¤ą¤ ą¤øą„ą¤µą¤øą„ऄ ą¤øą¤®ą„ą¤¦ą¤¾ą¤Æ ą¤¬ą¤Øą¤¾ą¤Øą„ ą¤ą„ ą¤²ą¤æą¤ ą¤ą¤®ą¤ą¤¤ą„रित ą¤ą¤°ą¤¤ą¤¾ ą¤¹ą„ą„¤ यदि ą¤ą¤Ŗ ą¤ą¤æą¤øą„ ą¤ą„ ą¤ą¤®ą¤ą¤¤ą„रित ą¤Øą¤¹ą„ą¤ ą¤ą¤°ą¤¤ą„ ą¤¹ą„ą¤, ą¤¤ą„ ą¤ą¤Ŗ ą¤Ŗą„ą¤°ą¤¤ą„ą¤ą„षा ą¤øą„ą¤ą„ ą¤ą„ ą¤²ą¤æą¤ ą¤øą¤¾ą¤ą¤Ø ą¤
प ą¤ą¤° ą¤øą¤ą¤¤ą„ ą¤¹ą„ą¤ ą¤ą¤° हम ą¤ą¤²ą„द ą¤¹ą„ ą¤ą¤ ą¤ą„ą¤ ą¤¦ą„ą¤ą¤ą„ą„¤ą„¤"
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr ""
@@ -524,8 +534,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "ą¤ą„वल ą¤
ą¤ą„षर, ą¤øą¤ą¤ą„या, ą¤°ą¤æą¤ą„त ą¤øą„ą¤„ान, ą¤”ą„ą¤¶ ą¤ą¤° ą¤
ą¤ą¤”ą¤°ą¤øą„ą¤ą„र ą¤¹ą„ ą¤øą¤ą¤¤ą„ ą¤¹ą„ą¤ą„¤ ą¤ą¤® ą¤øą„ ą¤ą¤® 4 ą¤
ą¤ą„षर ą¤²ą¤ą¤¬ą¤¾ ą¤¹ą„ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą¤æą¤, ą¤²ą„ą¤ą¤æą¤Ø 32 ą¤
ą¤ą„ą¤·ą¤°ą„ą¤ ą¤øą„ ą¤
ą¤§ą¤æą¤ ą¤²ą¤ą¤¬ą¤¾ ą¤Øą¤¹ą„ą¤ ą¤¹ą„ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą¤æą¤ą„¤ą„¤"
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -539,7 +549,7 @@ msgstr "ą¤ą„वल ą¤
ą¤ą„षर, ą¤øą¤ą¤ą„या, ą¤°ą¤æą¤ą„त सą„
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "ą¤ą„ą¤ą¤øą¤æą¤²"
@@ -690,7 +700,7 @@ msgid "Clear all storage data (restart after this)"
msgstr ""
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "ą¤ą„ą¤ ą¤ą„ą¤µą„ą¤°ą„ साफ़ ą¤ą¤°ą„ą¤"
@@ -698,6 +708,11 @@ msgstr "ą¤ą„ą¤ ą¤ą„ą¤µą„ą¤°ą„ साफ़ ą¤ą¤°ą„ą¤"
msgid "click here"
msgstr ""
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -728,11 +743,15 @@ msgstr "ą¤ą¤µą¤æ ą¤¬ą¤ą¤¦ ą¤ą¤°ą„ą¤"
msgid "Close image viewer"
msgstr "ą¤ą¤µą¤æ ą¤¬ą¤ą¤¦ ą¤ą¤°ą„ą¤"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "ą¤Øą„ą¤µą¤æą¤ą„शन पाद ą¤¬ą¤ą¤¦ ą¤ą¤°ą„ą¤"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr ""
@@ -740,7 +759,7 @@ msgstr ""
msgid "Closes password update alert"
msgstr ""
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr ""
@@ -773,7 +792,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr ""
@@ -837,7 +856,7 @@ msgstr "ą¤ą¤Øą„ą¤ą„ą¤ą¤æą¤ą¤ ..ą„¤"
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "ą¤øą¤¾ą¤®ą¤ą„ą¤°ą„ ą¤«ą¤¼ą¤æą¤²ą„ą¤ą¤°ą¤æą¤ą¤"
@@ -903,7 +922,7 @@ msgstr ""
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr ""
@@ -919,7 +938,7 @@ msgstr "ą¤ą„पą„"
msgid "Copy link to list"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr ""
@@ -927,7 +946,7 @@ msgstr ""
msgid "Copy link to profile"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤ą„ą¤ą„ą¤øą„ą¤ ą¤ą„ą¤Ŗą„ ą¤ą¤°ą„ą¤"
@@ -983,7 +1002,7 @@ msgstr ""
msgid "Created by you"
msgstr ""
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr ""
@@ -1060,11 +1079,11 @@ msgstr "ą¤®ą„ą¤°ą¤¾ ą¤ą¤¾ą¤¤ą¤¾ ą¤¹ą¤ą¤¾ą¤ą¤"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤ą„ ą¤¹ą¤ą¤¾ą¤ą¤"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "ą¤ą¤ø ą¤Ŗą„ą¤øą„ą¤ ą¤ą„ ą¤”ą„ą¤²ą„ą¤ ą¤ą¤°ą„ą¤?"
@@ -1087,7 +1106,7 @@ msgstr "विवरण"
#~ msgid "Developer Tools"
#~ msgstr "ą¤”ą„ą¤µą¤²ą¤Ŗą¤° ą¤ą¤Ŗą¤ą¤°ą¤£"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr ""
@@ -1095,15 +1114,15 @@ msgstr ""
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr ""
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "ą¤”ą„ą¤°ą¤¾ą¤«ą„ą¤ ą¤¹ą¤ą¤¾ą¤ą¤"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr ""
@@ -1182,7 +1201,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1254,6 +1273,7 @@ msgstr "ą¤®ą„ą¤°ą„ ą¤Ŗą„ą¤°ą„ą¤«ą¤¼ą¤¾ą¤ą¤² ą¤øą¤ą¤Ŗą¤¾ą¤¦ą¤æą¤¤ ą¤ą¤°ą„
msgid "Edit Profile"
msgstr "ą¤®ą„ą¤°ą„ ą¤Ŗą„ą¤°ą„ą¤«ą¤¼ą¤¾ą¤ą¤² ą¤øą¤ą¤Ŗą¤¾ą¤¦ą¤æą¤¤ ą¤ą¤°ą„ą¤"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "ą¤ą¤”ą¤æą¤ ą¤øą„ą¤µą„औ ą¤«ą„ą¤”"
@@ -1336,6 +1356,11 @@ msgstr ""
msgid "Enter a name for this App Password"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr ""
@@ -1385,7 +1410,7 @@ msgstr "ą¤
ą¤Ŗą¤Øą„ ą¤Æą„ą¤ą¤¼ą¤°ą¤Øą„म ą¤ą¤° ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤” द
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr ""
@@ -1456,7 +1481,7 @@ msgstr ""
msgid "Failed to create the list. Check your internet connection and try again."
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr ""
@@ -1478,8 +1503,8 @@ msgid "Feed offline"
msgstr "ą¤«ą¤¼ą„ą¤” ą¤ą¤«ą¤¼ą¤²ą¤¾ą¤ą¤Ø हą„"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "ą¤«ą¤¼ą„ą¤” ą¤Ŗą„ą¤°ą¤¾ą¤„ą¤®ą¤æą¤ą¤¤ą¤¾"
+#~ msgid "Feed Preferences"
+#~ msgstr "ą¤«ą¤¼ą„ą¤” ą¤Ŗą„ą¤°ą¤¾ą¤„ą¤®ą¤æą¤ą¤¤ą¤¾"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1527,11 +1552,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr ""
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr ""
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr ""
@@ -1628,6 +1653,7 @@ msgid "Following {0}"
msgstr ""
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1667,7 +1693,7 @@ msgstr "ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤” ą¤ą„ल ą¤ą¤"
msgid "Forgot Password"
msgstr "ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤” ą¤ą„ल ą¤ą¤"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr ""
@@ -1700,7 +1726,7 @@ msgstr "वापस ą¤ą¤¾ą¤"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1717,6 +1743,10 @@ msgstr "ą¤
ą¤ą¤²ą¤¾"
msgid "Handle"
msgstr "ą¤¹ą„ą¤ą¤”ल"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1755,7 +1785,7 @@ msgctxt "action"
msgid "Hide"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr ""
@@ -1764,7 +1794,7 @@ msgstr ""
msgid "Hide the content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr ""
@@ -1913,7 +1943,7 @@ msgstr ""
msgid "Input your user handle"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr ""
@@ -2015,7 +2045,7 @@ msgstr "ą¤
ą¤§ą¤æą¤ ą¤ą¤¾ą¤Øą„ą¤"
msgid "Learn more about this warning"
msgstr "ą¤ą¤ø ą¤ą„ą¤¤ą¤¾ą¤µą¤Øą„ ą¤ą„ ą¤¬ą¤¾ą¤°ą„ ą¤®ą„ą¤ ą¤
ą¤§ą¤æą¤ ą¤ą¤¾ą¤Øą„ą¤"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr ""
@@ -2091,7 +2121,7 @@ msgstr ""
msgid "Likes"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr ""
@@ -2148,7 +2178,7 @@ msgstr "ą¤
ą¤§ą¤æą¤ ą¤Ŗą„ą¤øą„ą¤ ą¤²ą„ą¤” ą¤ą¤°ą„ą¤"
msgid "Load new notifications"
msgstr "ą¤Øą¤ ą¤øą„ą¤ą¤Øą¤¾ą¤ą¤ ą¤²ą„ą¤” ą¤ą¤°ą„ą¤"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2174,7 +2204,7 @@ msgstr ""
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr ""
@@ -2186,6 +2216,10 @@ msgstr "ą¤ą¤ø ą¤ą¤¾ą¤¤ą„ ą¤®ą„ą¤ ą¤²ą„ą¤ ą¤ą¤Ø ą¤ą¤°ą„ą¤ ą¤ą„ स
msgid "Make sure this is where you intend to go!"
msgstr "यह ą¤øą„ą¤Øą¤æą¤¶ą„ą¤ą¤æą¤¤ ą¤ą¤°ą¤Øą„ ą¤ą„ ą¤²ą¤æą¤ ą¤ą¤æ ą¤ą¤Ŗ ą¤ą¤¹ą¤¾ą¤ ą¤ą¤¾ą¤Øą¤¾ ą¤ą¤¾ą¤¹ą¤¤ą„ ą¤¹ą„ą¤!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2207,7 +2241,7 @@ msgid "Mentioned users"
msgstr ""
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "ą¤®ą„ą¤Øą„"
@@ -2216,7 +2250,7 @@ msgid "Message from server: {0}"
msgstr ""
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2247,7 +2281,7 @@ msgstr ""
msgid "Moderation list updated"
msgstr ""
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "ą¤®ą„ą¤”ą¤°ą„ą¤¶ą¤Ø ą¤øą„ą¤ą¤æą¤Æą¤¾ą¤"
@@ -2274,7 +2308,7 @@ msgstr "ą¤
ą¤§ą¤æą¤ ą¤«ą¤¼ą„ą¤”"
msgid "More options"
msgstr "ą¤
ą¤§ą¤æą¤ ą¤µą¤æą¤ą¤²ą„प"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤µą¤æą¤ą¤²ą„प"
@@ -2286,6 +2320,14 @@ msgstr ""
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "ą¤ą¤¾ą¤¤ą¤¾ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤"
@@ -2294,6 +2336,18 @@ msgstr "ą¤ą¤¾ą¤¤ą¤¾ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤"
msgid "Mute accounts"
msgstr "ą¤ą¤¾ą¤¤ą„ą¤ ą¤ą„ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr ""
@@ -2306,15 +2360,27 @@ msgstr "ą¤ą¤Ø ą¤ą¤¾ą¤¤ą„ą¤ ą¤ą„ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤?"
msgid "Mute this List"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "ą¤„ą„ą¤°ą„औ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr ""
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "ą¤®ą„ą¤Æą„ą¤ ą¤ą¤æą¤ ą¤ą¤ ą¤ą¤¾ą¤¤ą„"
@@ -2327,6 +2393,10 @@ msgstr "ą¤®ą„ą¤Æą„ą¤ ą¤ą¤æą¤ ą¤ą¤ ą¤ą¤¾ą¤¤ą„"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "ą¤®ą„ą¤Æą„ą¤ ą¤ą¤æą¤ ą¤ą¤ ą¤ą¤¾ą¤¤ą„ą¤ ą¤ą„ ą¤Ŗą„ą¤øą„ą¤ ą¤ą¤Ŗą¤ą„ ą¤«ą¤¼ą„ą¤” ą¤ą¤° ą¤ą¤Ŗą¤ą„ ą¤øą„ą¤ą¤Øą¤¾ą¤ą¤ ą¤øą„ ą¤¹ą¤ą¤¾ ą¤¦ą„ ą¤ą¤¾ą¤¤ą„ ą¤¹ą„ą¤ą„¤ ą¤®ą„ą¤Æą„ą¤ ą¤Ŗą„ą¤°ą„ तरह ą¤øą„ ą¤Øą¤æą¤ą„ ą¤¹ą„ą¤."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą¤Øą¤¾ ą¤Øą¤æą¤ą„ हą„. ą¤®ą„ą¤Æą„ą¤ ą¤ą¤æą¤ ą¤ą¤ ą¤ą¤¾ą¤¤ą„ ą¤ą¤Ŗą¤ą„ साऄ ą¤ą¤ą¤ą¤°ą„ą¤ą„ą¤ ą¤ą¤° ą¤øą¤ą¤¤ą„ ą¤¹ą„ą¤, ą¤²ą„ą¤ą¤æą¤Ø ą¤ą¤Ŗ ą¤ą¤Øą¤ą„ ą¤Ŗą„ą¤øą„ą¤ ą¤Øą¤¹ą„ą¤ ą¤¦ą„ą¤ą„ą¤ą¤ą„ या ą¤ą¤Øą¤øą„ ą¤øą„ą¤ą¤Øą¤¾ą¤ą¤ ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„त ą¤Øą¤¹ą„ą¤ ą¤ą¤°ą„ą¤ą¤ą„ą„¤"
@@ -2390,6 +2460,10 @@ msgstr "ą¤
ą¤Ŗą¤Øą„ ą¤«ą¤¼ą„ą¤²ą„ą¤
ą¤°ą„ą¤ø ą¤ą¤° ą¤”ą„ą¤ą¤¾ तठप
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2411,7 +2485,7 @@ msgstr ""
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr ""
@@ -2496,8 +2570,8 @@ msgid "No results found for \"{query}\""
msgstr "\"{query}\" ą¤ą„ ą¤²ą¤æą¤ ą¤ą„ठपरिणाम ą¤Øą¤¹ą„ą¤ मिला"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "{query} ą¤ą„ ą¤²ą¤æą¤ ą¤ą„ठपरिणाम ą¤Øą¤¹ą„ą¤ मिला\""
@@ -2523,7 +2597,7 @@ msgstr ""
msgid "Not right now"
msgstr ""
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr ""
@@ -2561,7 +2635,7 @@ msgstr ""
msgid "Onboarding reset"
msgstr ""
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "ą¤ą¤ या ą¤
ą¤§ą¤æą¤ ą¤ą¤µą¤æą¤Æą¤¾ą¤ alt पाठयाद ą¤ą¤¤ą„ ą¤¹ą„ą¤ą„¤ą„¤"
@@ -2578,8 +2652,12 @@ msgstr ""
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr ""
@@ -2587,6 +2665,10 @@ msgstr ""
msgid "Open links with in-app browser"
msgstr ""
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "ą¤ą¤Ŗą¤Ø ą¤Øą„ą¤µą¤æą¤ą„शन"
@@ -2663,6 +2745,7 @@ msgstr "ą¤®ą„ą¤”ą¤°ą„ą¤¶ą¤Ø ą¤øą„ą¤ą¤æą¤ą¤ą„स ą¤ą„ą¤²ą„ą¤"
msgid "Opens password reset form"
msgstr ""
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr ""
@@ -2842,7 +2925,7 @@ msgstr ""
msgid "Please Verify Your Email"
msgstr ""
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr ""
@@ -2854,8 +2937,8 @@ msgstr ""
msgid "Porn"
msgstr ""
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr ""
@@ -2865,7 +2948,7 @@ msgctxt "description"
msgid "Post"
msgstr "ą¤Ŗą„ą¤øą„ą¤"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr ""
@@ -2875,11 +2958,11 @@ msgstr ""
msgid "Post by @{0}"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "ą¤ą„पा ą¤Ŗą„ą¤øą„ą¤"
@@ -2891,14 +2974,22 @@ msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤ą¤¾ą¤·ą¤¾"
msgid "Post Languages"
msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤ą¤¾ą¤·ą¤¾"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤Øą¤¹ą„ą¤ मिला"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr ""
@@ -2963,11 +3054,11 @@ msgstr ""
msgid "Public, shareable lists which can drive feeds."
msgstr "ą¤øą¤¾ą¤°ą„ą¤µą¤ą¤Øą¤æą¤, ą¤øą¤¾ą¤ą¤¾ ą¤ą¤°ą¤Øą„ ą¤Æą„ą¤ą„य ą¤øą„ą¤ą¤æą¤Æą¤¾ą¤ ą¤ą„ ą¤«ą¤¼ą„ą¤” ą¤ą¤²ą¤¾ ą¤øą¤ą¤¤ą„ ą¤¹ą„ą¤ą„¤"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr ""
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr ""
@@ -3001,6 +3092,7 @@ msgstr "ą¤
ą¤Øą„ą¤¶ą¤ą¤øą¤æą¤¤ ą¤«ą¤¼ą„ą¤”"
msgid "Recommended Users"
msgstr "ą¤
ą¤Øą„ą¤¶ą¤ą¤øą¤æą¤¤ ą¤²ą„ą¤"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3038,6 +3130,10 @@ msgstr "ą¤ą¤µą¤æ ą¤Øą¤æą¤ą¤¾ą¤²ą„ą¤"
msgid "Remove image preview"
msgstr "ą¤ą¤µą¤æ ą¤Ŗą„ą¤°ą„ą¤µą¤¾ą¤µą¤²ą„ą¤ą¤Ø ą¤Øą¤æą¤ą¤¾ą¤²ą„ą¤"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr ""
@@ -3072,7 +3168,7 @@ msgstr ""
msgid "Replies to this thread are disabled"
msgstr ""
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr ""
@@ -3082,7 +3178,7 @@ msgid "Reply Filters"
msgstr "ą¤«ą¤æą¤²ą„ą¤ą¤°"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr ""
@@ -3104,7 +3200,7 @@ msgid "Report List"
msgstr "ą¤°ą¤æą¤Ŗą„ą¤°ą„ą¤ ą¤øą„ą¤ą„"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "ą¤°ą¤æą¤Ŗą„ą¤°ą„ą¤ ą¤Ŗą„ą¤øą„ą¤"
@@ -3129,11 +3225,11 @@ msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤¦ą„ą¤¬ą¤¾ą¤°ą¤¾ ą¤Ŗą„ą¤øą„ą¤ ą¤ą¤°ą„ठया
msgid "Reposted By"
msgstr "ą¤¦ą„ą¤µą¤¾ą¤°ą¤¾ ą¤¦ą„ą¤¬ą¤¾ą¤°ą¤¾ ą¤Ŗą„ą¤øą„ą¤ ą¤ą¤æą¤Æą¤¾ ą¤ą¤Æą¤¾"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr ""
@@ -3141,7 +3237,7 @@ msgstr ""
msgid "reposted your post"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr ""
@@ -3292,9 +3388,9 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3304,11 +3400,19 @@ msgstr ""
msgid "Search"
msgstr "ą¤ą„ą¤"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3319,6 +3423,22 @@ msgstr ""
msgid "Security Step Required"
msgstr "ą¤øą„ą¤°ą¤ą„षा ą¤ą¤°ą¤£ ą¤ą¤µą¤¶ą„यą¤"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr ""
@@ -3528,7 +3648,7 @@ msgid "Share"
msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "ą¤¶ą„ą¤Æą¤°"
@@ -3561,9 +3681,9 @@ msgstr ""
msgid "Show follows similar to {0}"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr ""
@@ -3731,7 +3851,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr ""
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr ""
@@ -3789,7 +3909,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "ą¤ą¤ø ą¤øą„ą¤ą„ ą¤ą„ ą¤øą¤¬ą„ą¤øą¤ą„ą¤°ą¤¾ą¤ą¤¬ ą¤ą¤°ą„ą¤"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "ą¤
ą¤Øą„ą¤¶ą¤ą¤øą¤æą¤¤ ą¤²ą„ą¤"
@@ -3833,6 +3953,14 @@ msgstr "ą¤Ŗą„ą¤°ą¤£ą¤¾ą¤²ą„"
msgid "System log"
msgstr "ą¤øą¤æą¤øą„ą¤ą¤® ą¤²ą„ą¤"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "ą¤²ą¤ą¤¬ą¤¾"
@@ -3856,6 +3984,10 @@ msgstr "ą¤¶ą¤°ą„ą¤¤ą„ą¤"
msgid "Terms of Service"
msgstr "ą¤øą„ą¤µą¤¾ ą¤ą„ ą¤¶ą¤°ą„ą¤¤ą„ą¤"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3881,7 +4013,7 @@ msgstr "ą¤ą„ą¤Ŗą„ą¤°ą¤¾ą¤ą¤ ą¤Øą„ą¤¤ą¤æ ą¤ą„ <0/> पर ą¤øą„ą¤„ान
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "ą¤¹ą„ ą¤øą¤ą¤¤ą¤¾ ą¤¹ą„ ą¤ą¤æ यह ą¤Ŗą„ą¤øą„ą¤ ą¤¹ą¤ą¤¾ ą¤¦ą„ ą¤ą¤ ą¤¹ą„ą„¤"
@@ -4047,7 +4179,7 @@ msgstr ""
msgid "This name is already in use"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "ą¤ą¤ø ą¤Ŗą„ą¤øą„ą¤ ą¤ą„ ą¤¹ą¤ą¤¾ दिया ą¤ą¤Æą¤¾ ą¤¹ą„ą„¤ą„¤"
@@ -4071,7 +4203,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "यह ą¤ą„ą¤¤ą¤¾ą¤µą¤Øą„ ą¤ą„वल ą¤®ą„ą¤”िया ą¤øą¤ą¤²ą¤ą„न ą¤Ŗą„ą¤øą„ą¤ ą¤ą„ ą¤²ą¤æą¤ ą¤ą¤Ŗą¤²ą¤¬ą„ध ą¤¹ą„ą„¤"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr ""
@@ -4088,6 +4224,10 @@ msgstr "ą¤„ą„ą¤°ą„औ ą¤®ą„ą¤”"
msgid "Threads Preferences"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "ą¤”ą„ą¤°ą„ą¤Ŗą¤”ą¤¾ą¤ą¤Ø ą¤ą„ą¤ą¤² ą¤ą¤°ą„ą¤"
@@ -4096,9 +4236,9 @@ msgstr "ą¤”ą„ą¤°ą„ą¤Ŗą¤”ą¤¾ą¤ą¤Ø ą¤ą„ą¤ą¤² ą¤ą¤°ą„ą¤"
msgid "Transformations"
msgstr "ą¤Ŗą¤°ą¤æą¤µą¤°ą„ą¤¤ą¤Ø"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "ą¤
ą¤Øą„ą¤µą¤¾ą¤¦"
@@ -4163,15 +4303,24 @@ msgstr ""
msgid "Unlike"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr ""
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "ą¤
ą¤Øą¤®ą„ą¤Æą„ą¤ ą¤ą¤¾ą¤¤ą¤¾"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "ą¤„ą„ą¤°ą„औ ą¤ą„ ą¤
ą¤Øą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤"
@@ -4372,6 +4521,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4400,7 +4553,11 @@ msgstr "हम ą¤ą¤Ŗą¤ą„ ą¤¹ą¤®ą¤¾ą¤°ą„ ą¤øą„ą¤µą¤¾ ą¤®ą„ą¤ शामि
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr ""
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr ""
@@ -4421,7 +4578,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "ą¤ą¤ø {collectionName} ą¤ą„ साऄ ą¤ą„या ą¤®ą„ą¤¦ą„दा हą„?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr ""
@@ -4442,11 +4599,11 @@ msgstr ""
msgid "Wide"
msgstr "ą¤ą„औ़ा"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "ą¤Ŗą„ą¤øą„ą¤ ą¤²ą¤æą¤ą„"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "ą¤
पना ą¤ą¤µą¤¾ą¤¬ ą¤¦ą„ą¤"
@@ -4511,7 +4668,7 @@ msgstr ""
msgid "You don't have any saved feeds."
msgstr "ą¤ą¤Ŗą¤ą„ पास ą¤ą„ą¤ ą¤øą¤¹ą„ą¤ą„ ą¤ą¤ ą¤«ą¤¼ą„ą¤” ą¤Øą¤¹ą„ą¤ हą„."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "ą¤ą¤Ŗą¤Øą„ ą¤²ą„ą¤ą¤ ą¤ą„ ą¤
ą¤µą¤°ą„ą¤¦ą„ध ą¤ą¤æą¤Æą¤¾ ą¤¹ą„ ą¤Æą¤¾ ą¤ą¤Ŗą¤Øą„ ą¤²ą„ą¤ą¤ ą¤¦ą„ą¤µą¤¾ą¤°ą¤¾ ą¤
ą¤µą¤°ą„ą¤¦ą„ध ą¤ą¤æą¤Æą¤¾ ą¤¹ą„ą„¤ą„¤"
@@ -4551,6 +4708,10 @@ msgstr "ą¤ą¤Ŗą¤Øą„ ą¤
ą¤ą„ ą¤¤ą¤ ą¤ą„ą¤ ą¤ą¤Ŗ ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤” न
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "ą¤ą¤Ŗą¤Øą„ ą¤
ą¤ą„ ą¤¤ą¤ ą¤ą„ą¤ ą¤ą¤¾ą¤¤ą¤¾ ą¤®ą„ą¤Æą„ą¤ ą¤Øą¤¹ą„ą¤ ą¤ą¤æą¤Æą¤¾ हą„. ą¤ą¤æą¤øą„ ą¤ą¤¾ą¤¤ą„ ą¤ą„ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą¤Øą„ ą¤ą„ लिą¤, ą¤ą¤Øą¤ą„ ą¤Ŗą„ą¤°ą„ą¤«ą¤¼ą¤¾ą¤ą¤² पर ą¤ą¤¾ą¤ą¤ ą¤ą¤° ą¤ą¤Øą¤ą„ ą¤ą¤¾ą¤¤ą„ ą¤ą„ ą¤®ą„ą¤Øą„ ą¤øą„ \"ą¤ą¤¾ą¤¤ą¤¾ ą¤®ą„ą¤Æą„ą¤ ą¤ą¤°ą„ą¤\" ą¤ą„ą¤Øą„ą¤ą„¤"
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr ""
@@ -4559,11 +4720,11 @@ msgstr ""
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr ""
@@ -4649,11 +4810,15 @@ msgstr ""
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr ""
@@ -4668,7 +4833,7 @@ msgstr "ą¤ą¤Ŗą¤ą„ ą¤Ŗą„ą¤øą„ą¤, ą¤Ŗą¤øą¤ą¤¦ ą¤ą¤° ą¤¬ą„ą¤²ą„ठसा
msgid "Your profile"
msgstr "ą¤ą¤Ŗą¤ą„ ą¤Ŗą„ą¤°ą„ą¤«ą¤¼ą¤¾ą¤ą¤²"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr ""
diff --git a/src/locale/locales/id/messages.po b/src/locale/locales/id/messages.po
index 5697638a0f..4135b9f19d 100644
--- a/src/locale/locales/id/messages.po
+++ b/src/locale/locales/id/messages.po
@@ -92,7 +92,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Versi baru dari aplikasi ini telah tersedia. Harap perbarui untuk terus menggunakan aplikasi."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "Akses tautan navigasi dan pengaturan"
@@ -143,6 +143,7 @@ msgstr "Akun batal diblokir"
msgid "Account unmuted"
msgstr "Akun batal dibisukan"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -184,14 +185,22 @@ msgstr "Tambahkan detail"
msgid "Add details to report"
msgstr "Tambahkan detail ke laporan"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Tambahkan kartu tautan"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Tambahkan kartu tautan:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "Tambahkan DNS record berikut ke domain Anda:"
@@ -315,7 +324,7 @@ msgstr "Pengaturan kata sandi aplikasi"
msgid "App Passwords"
msgstr "Kata sandi Aplikasi"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "Ajukan banding peringatan konten"
@@ -342,15 +351,16 @@ msgstr "Tampilan"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "Anda yakin untuk menghapus kata sandi aplikasi \"{name}\"?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "Anda yakin untuk membuang draf ini?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "Anda yakin?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "Anda yakin? Ini tidak dapat dibatalkan."
@@ -372,15 +382,15 @@ msgstr "Ketelanjangan artistik atau non-erotis."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "Kembali"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "Kembali"
@@ -428,7 +438,7 @@ msgstr "Blokir Daftar ini"
msgid "Blocked"
msgstr "Diblokir"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Akun yang diblokir"
@@ -487,7 +497,7 @@ msgstr "Bluesky bersifat publik."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky menggunakan undangan untuk membangun komunitas yang sehat. Jika Anda tidak tahu orang lain yang memiliki undangan, Anda bisa mendaftar di daftar tunggu dan kami akan segera mengirimkan undangannya."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky tidak akan menampilkan profil dan postingan Anda ke pengguna yang tidak login. Aplikasi lain mungkin tidak menghormati permintaan ini. Ini tidak membuat akun Anda menjadi privat."
@@ -539,8 +549,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Hanya dapat terdiri dari huruf, angka, spasi, tanda hubung dan garis bawah. Minimal 4 karakter, namun tidak boleh lebih dari 32 karakter."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -554,7 +564,7 @@ msgstr "Hanya dapat terdiri dari huruf, angka, spasi, tanda hubung dan garis baw
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "Batal"
@@ -711,7 +721,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Hapus semua data penyimpanan (mulai ulang setelah ini)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Hapus kueri pencarian"
@@ -719,6 +729,11 @@ msgstr "Hapus kueri pencarian"
msgid "click here"
msgstr "klik di sini"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -749,11 +764,15 @@ msgstr "Tutup gambar"
msgid "Close image viewer"
msgstr "Tutup penampil gambar"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "Tutup footer navigasi"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "Menutup bilah navigasi bawah"
@@ -761,7 +780,7 @@ msgstr "Menutup bilah navigasi bawah"
msgid "Closes password update alert"
msgstr "Menutup peringatan pembaruan kata sandi"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "Menutup penyusun postingan dan membuang draf"
@@ -794,7 +813,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "Buat postingan dengan panjang hingga {MAX_GRAPHEME_LENGTH} karakter"
@@ -858,7 +877,7 @@ msgstr "Menghubungkan..."
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Penyaring Konten"
@@ -924,7 +943,7 @@ msgstr "Menyalin versi build ke papan klip"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "Disalin ke papan klip"
@@ -940,7 +959,7 @@ msgstr "Salin"
msgid "Copy link to list"
msgstr "Salin tautan ke daftar"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Salin tautan ke postingan"
@@ -948,7 +967,7 @@ msgstr "Salin tautan ke postingan"
msgid "Copy link to profile"
msgstr "Salin tautan ke profil"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "Salin teks postingan"
@@ -1004,7 +1023,7 @@ msgstr "Dibuat oleh <0/>"
msgid "Created by you"
msgstr "Dibuat oleh Anda"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "Buat kartu dengan gambar kecil. Tautan kartu ke {url}"
@@ -1085,11 +1104,11 @@ msgstr "Hapus akun saya"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Hapus postingan"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "Hapus postingan ini?"
@@ -1116,7 +1135,7 @@ msgstr "Deskripsi"
#~ msgid "Developer Tools"
#~ msgstr "Alat Pengembang"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "Apakah Anda ingin mengatakan sesuatu?"
@@ -1124,15 +1143,15 @@ msgstr "Apakah Anda ingin mengatakan sesuatu?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Buang"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Buang draf"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Cegah aplikasi untuk menampilkan akun saya ke pengguna yang tidak login"
@@ -1211,7 +1230,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1283,6 +1302,7 @@ msgstr "Edit profil"
msgid "Edit Profile"
msgstr "Edit Profil"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Edit Feed Tersimpan"
@@ -1365,6 +1385,11 @@ msgstr "Akhir feed"
msgid "Enter a name for this App Password"
msgstr "Masukkan nama untuk Sandi Aplikasi ini"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "Masukkan Kode Konfirmasi"
@@ -1418,7 +1443,7 @@ msgstr "Masukkan nama pengguna dan kata sandi Anda"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Eror:"
@@ -1489,7 +1514,7 @@ msgstr "Gagal membuat kata sandi aplikasi."
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "Gagal membuat daftar. Periksa koneksi internet Anda dan coba lagi."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "Gagal menghapus postingan, silakan coba lagi"
@@ -1511,8 +1536,8 @@ msgid "Feed offline"
msgstr "Feed offline"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "Preferensi Feed"
+#~ msgid "Feed Preferences"
+#~ msgstr "Preferensi Feed"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1560,11 +1585,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr "Temukan akun untuk diikuti"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Temukan pengguna di Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Temukan pengguna dengan alat pencarian di sebelah kanan"
@@ -1668,6 +1693,7 @@ msgid "Following {0}"
msgstr "Mengikuti {0}"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1707,7 +1733,7 @@ msgstr "Lupa kata sandi"
msgid "Forgot Password"
msgstr "Lupa Kata Sandi"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "Dari <0/>"
@@ -1740,7 +1766,7 @@ msgstr "Kembali"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1757,6 +1783,10 @@ msgstr "Berikutnya"
msgid "Handle"
msgstr "Handle"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1799,7 +1829,7 @@ msgctxt "action"
msgid "Hide"
msgstr "Sembunyikan"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Sembunyikan postingan"
@@ -1808,7 +1838,7 @@ msgstr "Sembunyikan postingan"
msgid "Hide the content"
msgstr "Sembunyikan konten"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "Sembunyikan postingan ini?"
@@ -1969,7 +1999,7 @@ msgstr "Masukkan kata sandi Anda"
msgid "Input your user handle"
msgstr "Masukkan handle pengguna Anda"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "Catatan posting tidak valid atau tidak didukung"
@@ -2071,7 +2101,7 @@ msgstr "Pelajari Lebih Lanjut"
msgid "Learn more about this warning"
msgstr "Pelajari lebih lanjut tentang peringatan ini"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Pelajari lebih lanjut tentang apa yang publik di Bluesky."
@@ -2155,7 +2185,7 @@ msgstr "menyukai postingan Anda"
msgid "Likes"
msgstr "Suka"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "Suka pada postingan ini"
@@ -2212,7 +2242,7 @@ msgstr "Muat postingan lainnya"
msgid "Load new notifications"
msgstr "Muat notifikasi baru"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2238,7 +2268,7 @@ msgstr "Catatan"
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "Visibilitas pengguna yang tidak login"
@@ -2253,6 +2283,10 @@ msgstr "Masuk ke akun yang tidak ada di daftar"
msgid "Make sure this is where you intend to go!"
msgstr "Pastikan ini adalah website yang Anda tuju!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2274,7 +2308,7 @@ msgid "Mentioned users"
msgstr "Pengguna yang disebutkan"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "Menu"
@@ -2286,7 +2320,7 @@ msgid "Message from server: {0}"
msgstr "Pesan dari server: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2317,7 +2351,7 @@ msgstr "Daftar moderasi dibuat"
msgid "Moderation list updated"
msgstr "Daftar moderasi diperbarui"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Daftar moderasi"
@@ -2344,7 +2378,7 @@ msgstr "Feed lainnya"
msgid "More options"
msgstr "Pilihan lainnya"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "Opsi posting lainnya"
@@ -2356,6 +2390,14 @@ msgstr "Balasan yang paling disukai lebih dulu"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Bisukan Akun"
@@ -2364,6 +2406,18 @@ msgstr "Bisukan Akun"
msgid "Mute accounts"
msgstr "Bisukan akun"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "Daftar akun yang dibisukan"
@@ -2376,15 +2430,27 @@ msgstr "Bisukan akun ini?"
msgid "Mute this List"
msgstr "Bisukan Daftar ini"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Bisukan utasan"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "Dibisukan"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Akun yang dibisukan"
@@ -2397,6 +2463,10 @@ msgstr "Akun yang Dibisukan"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "Postingan dari akun yang dibisukan akan dihilangkan dari feed dan notifikasi Anda. Pembisuan ini bersifat privat."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Pembisuan akun bersifat privat. Akun yang dibisukan tetap dapat berinteraksi dengan Anda, namun Anda tidak akan melihat postingan atau notifikasi dari mereka."
@@ -2460,6 +2530,10 @@ msgstr "Tidak akan lagi kehilangan akses ke data dan pengikut Anda."
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2481,7 +2555,7 @@ msgstr "Kata sandi baru"
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "Postingan baru"
@@ -2569,8 +2643,8 @@ msgid "No results found for \"{query}\""
msgstr "Tidak ada hasil ditemukan untuk \"{query}\""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "Tidak ada hasil ditemukan untuk {query}"
@@ -2596,7 +2670,7 @@ msgstr "Tidak ditemukan"
msgid "Not right now"
msgstr "Jangan sekarang"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Catatan: Bluesky merupakan jaringan terbuka dan publik. Pengaturan ini hanya akan membatasi visibilitas konten Anda pada aplikasi dan website Bluesky, dan aplikasi lain mungkin tidak mengindahkan pengaturan ini. Konten Anda mungkin tetap ditampilkan kepada pengguna yang tidak login oleh aplikasi dan website lain."
@@ -2634,7 +2708,7 @@ msgstr "Balasan terlama terlebih dahulu"
msgid "Onboarding reset"
msgstr "Atur ulang orientasi"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "Satu atau lebih gambar belum ada teks alt."
@@ -2651,8 +2725,12 @@ msgstr "Uups!"
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "Buka pemilih emoji"
@@ -2660,6 +2738,10 @@ msgstr "Buka pemilih emoji"
msgid "Open links with in-app browser"
msgstr "Buka tautan dengan browser dalam aplikasi"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Buka navigasi"
@@ -2736,6 +2818,7 @@ msgstr "Buka pengaturan moderasi"
msgid "Opens password reset form"
msgstr "Membuka formulir pengaturan ulang kata sandi"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "Membuka layar untuk mengedit Umpan Tersimpan"
@@ -2918,7 +3001,7 @@ msgstr "Mohon beri tahu kami mengapa menurut Anda peringatan konten ini salah di
msgid "Please Verify Your Email"
msgstr "Mohon Verifikasi Email Anda"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "Harap tunggu hingga kartu tautan Anda selesai dimuat"
@@ -2930,8 +3013,8 @@ msgstr ""
msgid "Porn"
msgstr "Pornografi"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "Posting"
@@ -2944,7 +3027,7 @@ msgstr "Posting"
#~ msgid "Post"
#~ msgstr "Posting"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "Postingan oleh {0}"
@@ -2954,11 +3037,11 @@ msgstr "Postingan oleh {0}"
msgid "Post by @{0}"
msgstr "Postingan oleh @{0}"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "Postingan dihapus"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Postingan disembunyikan"
@@ -2970,14 +3053,22 @@ msgstr "Bahasa postingan"
msgid "Post Languages"
msgstr "Bahasa Postingan"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Postingan tidak ditemukan"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "Postingan"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "Postingan disembunyikan"
@@ -3042,11 +3133,11 @@ msgstr "Daftar publik yang dapat dibagikan oleh pengguna untuk dibisukan atau di
msgid "Public, shareable lists which can drive feeds."
msgstr "Publik, daftar yang dapat dibagikan dan dapat berimbas ke feed."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "Publikasikan postingan"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "Publikasikan balasan"
@@ -3083,6 +3174,7 @@ msgstr "Feed Direkomendasikan"
msgid "Recommended Users"
msgstr "Pengguna Direkomendasikan"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3120,6 +3212,10 @@ msgstr "Hapus gambar"
msgid "Remove image preview"
msgstr "Hapus pratinjau gambar"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "Hapus postingan ulang"
@@ -3154,7 +3250,7 @@ msgstr "Balasan"
msgid "Replies to this thread are disabled"
msgstr "Balasan ke utas ini dinonaktifkan"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "Balas"
@@ -3164,7 +3260,7 @@ msgid "Reply Filters"
msgstr "Penyaring Balasan"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "Balas ke <0/>"
@@ -3186,7 +3282,7 @@ msgid "Report List"
msgstr "Laporkan Daftar"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Laporkan postingan"
@@ -3215,7 +3311,7 @@ msgstr "Posting ulang atau kutip postingan"
msgid "Reposted By"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
@@ -3223,7 +3319,7 @@ msgstr ""
#~ msgid "Reposted by {0})"
#~ msgstr "Diposting ulang oleh {0})"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "Diposting ulang oleh <0/>"
@@ -3231,7 +3327,7 @@ msgstr "Diposting ulang oleh <0/>"
msgid "reposted your post"
msgstr "posting ulang posting Anda"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "Posting ulang postingan ini"
@@ -3382,9 +3478,9 @@ msgstr "Gulir ke atas"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3394,11 +3490,19 @@ msgstr "Gulir ke atas"
msgid "Search"
msgstr "Cari"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3409,6 +3513,22 @@ msgstr "Cari pengguna"
msgid "Security Step Required"
msgstr "Langkah Keamanan Diperlukan"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "Lihat panduan ini"
@@ -3625,7 +3745,7 @@ msgid "Share"
msgstr "Bagikan"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Bagikan"
@@ -3658,9 +3778,9 @@ msgstr "Tampilkan embed dari {0}"
msgid "Show follows similar to {0}"
msgstr "Tampilkan berikut ini mirip dengan {0}"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "Tampilkan Lebih Lanjut"
@@ -3828,7 +3948,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr "Ada yang tidak beres. Periksa email Anda dan coba lagi."
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "Maaf! Sesi Anda telah berakhir. Silakan masuk lagi."
@@ -3890,7 +4010,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "Langganan ke daftar ini"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "Saran untuk Diikuti"
@@ -3934,6 +4054,14 @@ msgstr "Sistem"
msgid "System log"
msgstr "Log sistem"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "Tinggi"
@@ -3957,6 +4085,10 @@ msgstr "Ketentuan"
msgid "Terms of Service"
msgstr "Ketentuan Layanan"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3982,7 +4114,7 @@ msgstr "Kebijakan Hak Cipta telah dipindahkan ke <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "Postingan mungkin telah dihapus."
@@ -4162,7 +4294,7 @@ msgstr "Daftar ini kosong!"
msgid "This name is already in use"
msgstr "Nama ini sudah digunakan"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Postingan ini telah dihapus."
@@ -4186,7 +4318,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Peringatan ini hanya tersedia untuk postingan dengan lampiran media."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Ini akan menyembunyikan postingan ini dari feed Anda."
@@ -4203,6 +4339,10 @@ msgstr "Mode Utasan"
msgid "Threads Preferences"
msgstr "Preferensi Utas"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Beralih dropdown"
@@ -4211,9 +4351,9 @@ msgstr "Beralih dropdown"
msgid "Transformations"
msgstr "Transformasi"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Terjemahkan"
@@ -4281,15 +4421,24 @@ msgstr "Sayangnya, Anda tidak memenuhi syarat untuk membuat akun."
msgid "Unlike"
msgstr "Tidak suka"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "Bunyikan"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "Bunyikan Akun"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "Bunyikan utasan"
@@ -4494,6 +4643,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4522,7 +4675,11 @@ msgstr "Kami sangat senang Anda bergabung dengan kami!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "Mohon maaf, kami tidak dapat menyelesaikan daftar ini. Jika hal ini terus berlanjut, silakan hubungi pembuat daftar, @{handleOrDid}."
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Maaf, pencarian Anda tidak dapat dilakukan. Mohon coba lagi dalam beberapa menit."
@@ -4546,7 +4703,7 @@ msgstr "Apa yang bermasalah dengan {collectionName}?"
#~ msgstr "Apa selanjutnya?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "Apa kabar?"
@@ -4567,11 +4724,11 @@ msgstr "Siapa yang dapat membalas"
msgid "Wide"
msgstr "Lebar"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "Tulis postingan"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "Tulis balasan Anda"
@@ -4640,7 +4797,7 @@ msgstr "Anda tidak memiliki feed yang disimpan!"
msgid "You don't have any saved feeds."
msgstr "Anda tidak memiliki feed yang disimpan."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "Anda telah memblokir atau diblokir oleh penulis ini."
@@ -4680,6 +4837,10 @@ msgstr "Anda belum membuat kata sandi aplikasi. Anda dapat membuatnya dengan men
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "Anda belum membisukan akun lain. Untuk membisukan akun, kunjungi profil mereka dan pilih \"Bisukan akun\" pada menu di akun mereka."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "Anda harus berusia 18 tahun atau lebih untuk mengaktifkan konten dewasa."
@@ -4688,11 +4849,11 @@ msgstr "Anda harus berusia 18 tahun atau lebih untuk mengaktifkan konten dewasa.
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "Anda tidak akan lagi menerima notifikasi untuk utas ini"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "Anda sekarang akan menerima notifikasi untuk utas ini"
@@ -4782,11 +4943,15 @@ msgstr "Handle lengkap Anda akan menjadi <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "Kode undangan Anda disembunyikan saat masuk menggunakan Kata Sandi Aplikasi"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "Postingan Anda telah dipublikasikan"
@@ -4801,7 +4966,7 @@ msgstr "Postingan, suka, dan blokir Anda bersifat publik. Bisukan bersifat priva
msgid "Your profile"
msgstr "Profil Anda"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "Balasan Anda telah dipublikasikan"
diff --git a/src/locale/locales/it/messages.po b/src/locale/locales/it/messages.po
index bfa796a4fc..ac09dc1073 100644
--- a/src/locale/locales/it/messages.po
+++ b/src/locale/locales/it/messages.po
@@ -84,7 +84,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Ć disponibile una nuova versione dell'app. Aggiorna per continuare a utilizzarla."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "Accedi alle impostazioni di navigazione"
@@ -135,6 +135,7 @@ msgstr "Account sbloccato"
msgid "Account unmuted"
msgstr "Account non silenziato"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -176,14 +177,22 @@ msgstr "Aggiungi i dettagli"
msgid "Add details to report"
msgstr "Aggiungi dettagli da segnalare"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Aggiungi la scheda collegata al link"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Aggiungi la scheda relazionata al link:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "Aggiungi il seguente record DNS al tuo dominio:"
@@ -303,7 +312,7 @@ msgstr "Impostazioni della password dell'app"
msgid "App Passwords"
msgstr "Passwords dell'App"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "Ricorso contro l'avviso sui contenuti"
@@ -330,15 +339,16 @@ msgstr "Aspetto"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "Conferma di voler eliminare la password dell'app \"{name}\"?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "Conferma di voler eliminare questa bozza?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "Confermi?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "Vuoi proseguire? Questa operazione non può essere annullata."
@@ -360,15 +370,15 @@ msgstr "NuditĆ artistica o non erotica."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "Indietro"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "Indietro"
@@ -416,7 +426,7 @@ msgstr "Blocca questa Lista"
msgid "Blocked"
msgstr "Bloccato"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Accounts bloccati"
@@ -475,7 +485,7 @@ msgstr "Bluesky ĆØ pubblico."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky utilizza gli inviti per costruire una comunità più sana. Se non conosci nessuno con un invito, puoi iscriverti alla lista d'attesa e te ne invieremo uno al più presto."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky non mostrerĆ il tuo profilo e i tuoi post agli utenti disconnessi. Altre app potrebbero non rispettare questa richiesta. Questo non rende il tuo account privato."
@@ -527,8 +537,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Può contenere solo lettere, numeri, spazi, trattini e trattini bassi. Deve contenere almeno 4 caratteri, ma non più di 32 caratteri."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -542,7 +552,7 @@ msgstr "Può contenere solo lettere, numeri, spazi, trattini e trattini bassi. D
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "Cancella"
@@ -695,7 +705,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Cancella tutti i dati in archivio (poi ricomincia)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Annulla la ricerca"
@@ -703,6 +713,11 @@ msgstr "Annulla la ricerca"
msgid "click here"
msgstr "clicca qui"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -733,11 +748,15 @@ msgstr "Chiudi l'immagine"
msgid "Close image viewer"
msgstr "Chiudi il visualizzatore di immagini"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "Chiudi la navigazione del footer"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "Chiude la barra di navigazione in basso"
@@ -745,7 +764,7 @@ msgstr "Chiude la barra di navigazione in basso"
msgid "Closes password update alert"
msgstr "Chiude l'avviso di aggiornamento della password"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "Chiude l'editore del post ed elimina la bozza del post"
@@ -778,7 +797,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "Componi un post fino a {MAX_GRAPHEME_LENGTH} caratteri"
@@ -842,7 +861,7 @@ msgstr "Connessione in corso..."
msgid "Contact support"
msgstr "Contatta il supporto"
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Filtro dei contenuti"
@@ -908,7 +927,7 @@ msgstr "Versione di build copiata nella clipboard"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "Copiato nel clipboard"
@@ -924,7 +943,7 @@ msgstr "Copia"
msgid "Copy link to list"
msgstr "Copia il link alla lista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Copia il link al post"
@@ -932,7 +951,7 @@ msgstr "Copia il link al post"
msgid "Copy link to profile"
msgstr "Copia il link al profilo"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "Copia il testo del post"
@@ -988,7 +1007,7 @@ msgstr "Creato da <0/>"
msgid "Created by you"
msgstr "Creato da te"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "Crea una scheda con una miniatura. La scheda si collega a {url}"
@@ -1065,11 +1084,11 @@ msgstr "Cancella il mio account"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Elimina il post"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "Elimina questo post?"
@@ -1095,7 +1114,7 @@ msgstr "Descrizione"
#~ msgid "Developer Tools"
#~ msgstr "Strumenti per sviluppatori"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "Volevi dire qualcosa?"
@@ -1103,15 +1122,15 @@ msgstr "Volevi dire qualcosa?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Scartare"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Scarta la bozza"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Scoraggia le app dal mostrare il mio account agli utenti disconnessi"
@@ -1190,7 +1209,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1262,6 +1281,7 @@ msgstr "Modifica il profilo"
msgid "Edit Profile"
msgstr "Modifica il Profilo"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Modifica i feeds memorizzati"
@@ -1344,6 +1364,11 @@ msgstr "Fine del feed"
msgid "Enter a name for this App Password"
msgstr "Inserisci un nome per questa password dell'app"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "Inserire il codice di conferma"
@@ -1396,7 +1421,7 @@ msgstr "Inserisci il tuo nome di utente e la tua password"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Errore:"
@@ -1467,7 +1492,7 @@ msgstr "Impossibile creare la password dell'app."
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "Impossibile creare l'elenco. Controlla la connessione Internet e riprova."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "Non possiamo eliminare il post, riprova di nuovo"
@@ -1489,8 +1514,8 @@ msgid "Feed offline"
msgstr "Feed offline"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "Preferenze del feed"
+#~ msgid "Feed Preferences"
+#~ msgstr "Preferenze del feed"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1530,11 +1555,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr "Trova account da seguire"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Trova utenti su Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Trova gli utenti con lo strumento di ricerca sulla destra"
@@ -1634,6 +1659,7 @@ msgid "Following {0}"
msgstr "Seguiti {0}"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1673,7 +1699,7 @@ msgstr "Ho dimenticato il password"
msgid "Forgot Password"
msgstr "Ho dimenticato il Password"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "Da <0/>"
@@ -1706,7 +1732,7 @@ msgstr "Torna Indietro"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr "Vai a @{queryMaybeHandle}"
@@ -1723,6 +1749,10 @@ msgstr "Seguente"
msgid "Handle"
msgstr "Nome Utente"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr "Ci sono problemi?"
@@ -1761,7 +1791,7 @@ msgctxt "action"
msgid "Hide"
msgstr "Nascondi"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Nascondi il messaggio"
@@ -1770,7 +1800,7 @@ msgstr "Nascondi il messaggio"
msgid "Hide the content"
msgstr "Nascondere il contenuto"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "Vuoi nascondere questo post?"
@@ -1922,7 +1952,7 @@ msgstr "Inserisci la tua password"
msgid "Input your user handle"
msgstr "Inserisci il tuo identificatore"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "Protocollo del post non valido o non supportato"
@@ -2024,7 +2054,7 @@ msgstr "Ulteriori Informazioni"
msgid "Learn more about this warning"
msgstr "Ulteriori informazioni su questo avviso"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Scopri cosa ĆØ pubblico su Bluesky."
@@ -2104,7 +2134,7 @@ msgstr "ĆØ piaciuto il tuo post"
msgid "Likes"
msgstr "Mi piace"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "Mi Piace in questo post"
@@ -2161,7 +2191,7 @@ msgstr "Carica più post"
msgid "Load new notifications"
msgstr "Carica più notifiche"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2187,7 +2217,7 @@ msgstr "Log"
msgid "Log out"
msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "VisibilitĆ degli utenti non connettati"
@@ -2202,6 +2232,10 @@ msgstr "Accedi all'account che non ĆØ nella lista"
msgid "Make sure this is where you intend to go!"
msgstr "Assicurati che questo sia dove intendi andare!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2223,7 +2257,7 @@ msgid "Mentioned users"
msgstr "Utenti menzionati"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "Menù"
@@ -2235,7 +2269,7 @@ msgid "Message from server: {0}"
msgstr "Messaggio dal server: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2266,7 +2300,7 @@ msgstr "Lista di moderazione creata"
msgid "Moderation list updated"
msgstr "Lista di moderazione aggiornata"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Liste di moderazione"
@@ -2293,7 +2327,7 @@ msgstr "Altri feed"
msgid "More options"
msgstr "Altre opzioni"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "Altre impostazioni per il post"
@@ -2305,6 +2339,14 @@ msgstr "Dai priorità alle risposte con più likes"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Silenziare Account"
@@ -2313,6 +2355,18 @@ msgstr "Silenziare Account"
msgid "Mute accounts"
msgstr "Silenziare accounts"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "Silenziare la lista"
@@ -2325,15 +2379,27 @@ msgstr "Vuoi silenziare queste liste?"
msgid "Mute this List"
msgstr "Silenzia questa Lista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Silenzia questa discussione"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "Silenziato"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Account silenziato"
@@ -2346,6 +2412,10 @@ msgstr "Accounts Silenziati"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "I post degli account silenziati verranno rimossi dal tuo feed e dalle tue notifiche. Silenziare ĆØ completamente privato."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Silenziare un account è privato. Gli account silenziati possono interagire con te, ma non vedrai i loro post né riceverai le loro notifiche."
@@ -2409,6 +2479,10 @@ msgstr "Non perdere mai l'accesso ai tuoi follower e ai tuoi dati."
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2430,7 +2504,7 @@ msgstr "Nuovo Password"
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "Nuovo Post"
@@ -2518,8 +2592,8 @@ msgid "No results found for \"{query}\""
msgstr "Nessun risultato trovato per \"{query}\""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "Nessun risultato trovato per {query}"
@@ -2545,7 +2619,7 @@ msgstr "Non trovato"
msgid "Not right now"
msgstr "Non adesso"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Nota: Bluesky ĆØ una rete aperta e pubblica. Questa impostazione limita solo la visibilitĆ dei tuoi contenuti sull'app e sul sito Web di Bluesky e altre app potrebbero non rispettare questa impostazione. I tuoi contenuti potrebbero comunque essere mostrati agli utenti disconnessi da altre app e siti web."
@@ -2583,7 +2657,7 @@ msgstr "Prima le risposte più vecchie"
msgid "Onboarding reset"
msgstr "Reimpostazione dell'onboarding"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "A una o più immagini manca il testo alternativo."
@@ -2600,8 +2674,12 @@ msgstr "Ops!"
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "Apri il selettore emoji"
@@ -2609,6 +2687,10 @@ msgstr "Apri il selettore emoji"
msgid "Open links with in-app browser"
msgstr "Apri i links con il navigatore della app"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Apri la navigazione"
@@ -2685,6 +2767,7 @@ msgstr "Apre le impostazioni di moderazione"
msgid "Opens password reset form"
msgstr "Apre il modulo di reimpostazione della password"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "Apre la schermata per modificare i feed salvati"
@@ -2863,7 +2946,7 @@ msgstr "Spiegaci perchƩ ritieni che questo avviso sui contenuti sia stato appli
msgid "Please Verify Your Email"
msgstr "Verifica la tua email"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "Attendi il caricamento della scheda di collegamento"
@@ -2875,8 +2958,8 @@ msgstr ""
msgid "Porn"
msgstr "Porno"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "Post"
@@ -2889,7 +2972,7 @@ msgstr "Post"
#~ msgid "Post"
#~ msgstr "Publicació"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "Pubblicato da {0}"
@@ -2899,11 +2982,11 @@ msgstr "Pubblicato da {0}"
msgid "Post by @{0}"
msgstr "Pubblicato da @{0}"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "Post eliminato"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Post nascosto"
@@ -2915,14 +2998,22 @@ msgstr "Lingua del post"
msgid "Post Languages"
msgstr "Lingue del post"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Post non trovato"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "Post"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "Post nascosto"
@@ -2987,11 +3078,11 @@ msgstr "Elenchi pubblici e condivisibili di utenti da disattivare o bloccare in
msgid "Public, shareable lists which can drive feeds."
msgstr "Elenchi pubblici e condivisibili che possono gestire i feeds."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "Pubblica il post"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "Pubblica la risposta"
@@ -3028,6 +3119,7 @@ msgstr "Feeds consigliati"
msgid "Recommended Users"
msgstr "Utenti consigliati"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3065,6 +3157,10 @@ msgstr "Rimuovi l'immagine"
msgid "Remove image preview"
msgstr "Rimuovi l'anteprima dell'immagine"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "Rimuovi la ripubblicazione"
@@ -3099,7 +3195,7 @@ msgstr "Risposte"
msgid "Replies to this thread are disabled"
msgstr "Le risposte a questo thread sono disabilitate"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "Rispondi"
@@ -3109,7 +3205,7 @@ msgid "Reply Filters"
msgstr "Filtri di risposta"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "Rispondi a <0/>"
@@ -3131,7 +3227,7 @@ msgid "Report List"
msgstr "Segnala la lista"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Segnala il post"
@@ -3160,7 +3256,7 @@ msgstr "Ripubblicare o citare il post"
msgid "Reposted By"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
@@ -3168,7 +3264,7 @@ msgstr ""
#~ msgid "Reposted by {0})"
#~ msgstr "Ripubblicato da {0})"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "Ripubblicato da <0/>"
@@ -3176,7 +3272,7 @@ msgstr "Ripubblicato da <0/>"
msgid "reposted your post"
msgstr "ripubblicato il tuo post"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "Ripubblicazione di questo post"
@@ -3327,9 +3423,9 @@ msgstr "Scorri verso l'alto"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3339,11 +3435,19 @@ msgstr "Scorri verso l'alto"
msgid "Search"
msgstr "Cerca"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr "Cerca \"{query}\""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3354,6 +3458,22 @@ msgstr "Cerca utenti"
msgid "Security Step Required"
msgstr "Passaggio di sicurezza obbligatorio"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "Consulta questa guida"
@@ -3562,7 +3682,7 @@ msgid "Share"
msgstr "Condividi"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Condividi"
@@ -3595,9 +3715,9 @@ msgstr "Mostra incorporamenti di {0}"
msgid "Show follows similar to {0}"
msgstr "Mostra follows simile a {0}"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "Mostra di più"
@@ -3765,7 +3885,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr "Qualcosa ĆØ andato storto. Controlla la tua email e riprova."
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "Scusa! La tua sessione ĆØ scaduta. Per favore accedi di nuovo."
@@ -3823,7 +3943,7 @@ msgstr ""
msgid "Subscribe to this list"
msgstr "Iscriviti alla lista"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "Followers suggeriti"
@@ -3867,6 +3987,14 @@ msgstr "Sistema"
msgid "System log"
msgstr "Registro di sistema"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "Alto"
@@ -3890,6 +4018,10 @@ msgstr "Termini"
msgid "Terms of Service"
msgstr "Termini di servizio"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3915,7 +4047,7 @@ msgstr "La politica sul copyright ĆØ stata spostata a <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "Il post potrebbe essere stato cancellato."
@@ -4090,7 +4222,7 @@ msgstr "La lista ĆØ vuota!"
msgid "This name is already in use"
msgstr "Questo nome ĆØ giĆ in uso"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Questo post ĆØ stato cancellato."
@@ -4114,7 +4246,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Questo avviso ĆØ disponibile solo per i post con contenuti multimediali allegati."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Questo nasconderĆ il post dai tuoi feeds."
@@ -4131,6 +4267,10 @@ msgstr "ModalitĆ discussione"
msgid "Threads Preferences"
msgstr "Preferenze per le discussioni"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Attiva/disattiva il menu a discesa"
@@ -4139,9 +4279,9 @@ msgstr "Attiva/disattiva il menu a discesa"
msgid "Transformations"
msgstr "Trasformazioni"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Tradurre"
@@ -4209,15 +4349,24 @@ msgstr "Sfortunatamente, non soddisfi i requisiti per creare un account."
msgid "Unlike"
msgstr "Togli Mi piace"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "Riattiva"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "Riattiva questo account"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "Riattiva questa discussione"
@@ -4414,6 +4563,10 @@ msgstr ""
msgid "We ran out of posts from your follows. Here's the latest from <0/>."
msgstr "Abbiamo esaurito i posts dei tuoi follower. Ecco le ultime novitĆ da <0/>."
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4442,7 +4595,11 @@ msgstr "Siamo felici che tu ti unisca a noi!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "Siamo spiacenti, ma non siamo riusciti a risolvere questa lista. Se il problema persiste, contatta il creatore della lista, @{handleOrDid}."
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Siamo spiacenti, ma non ĆØ stato possibile completare la ricerca. Riprova tra qualche minuto."
@@ -4466,7 +4623,7 @@ msgstr "Qual ĆØ il problema con questo {collectionName}?"
#~ msgstr "¿Qué sigue?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "Come va?"
@@ -4487,11 +4644,11 @@ msgstr "Chi può rispondere"
msgid "Wide"
msgstr "Largo"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "Scrivi un post"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "Scrivi la tua risposta"
@@ -4551,7 +4708,7 @@ msgstr "Non hai salvato nessun feed!"
msgid "You don't have any saved feeds."
msgstr "Non hai salvato nessun feed."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "Hai bloccato l'autore o sei stato bloccato dall'autore."
@@ -4591,6 +4748,10 @@ msgstr "Non hai ancora creato alcuna password per l'app. Puoi crearne uno premen
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "Non hai ancora disattivato alcun account. Per disattivare un account, vai al suo profilo e seleziona \"Disattiva account\" dal menu del account."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "Devi avere almeno 18 anni per abilitare i contenuti per adulti."
@@ -4599,11 +4760,11 @@ msgstr "Devi avere almeno 18 anni per abilitare i contenuti per adulti."
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "Non riceverai più notifiche per questo filo di discussione"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "Adesso riceverai le notifiche per questa discussione"
@@ -4691,11 +4852,15 @@ msgstr "Il tuo nome di utente completo sarĆ <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "I tuoi codici di invito vengono celati quando accedi utilizzando una password per l'app"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "Il tuo post ĆØ stato pubblicato"
@@ -4710,7 +4875,7 @@ msgstr "I tuoi post, i tuoi Mi piace e i tuoi blocchi sono pubblici. I conti sil
msgid "Your profile"
msgstr "Il tuo profilo"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "La tua risposta ĆØ stata pubblicata"
diff --git a/src/locale/locales/ja/messages.po b/src/locale/locales/ja/messages.po
index a0ad5ffb8d..21f2e5e0fc 100644
--- a/src/locale/locales/ja/messages.po
+++ b/src/locale/locales/ja/messages.po
@@ -93,7 +93,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "ę°ćććć¼ćøć§ć³ć®ć¢ććŖćå©ēØåÆč½ć§ććē¶ē¶ćć¦ä½æēØććććć«ćÆć¢ćććć¼ććć¦ćć ććć"
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "ććć²ć¼ć·ć§ć³ćŖć³ćÆćØčØå®ć«ć¢ćÆć»ć¹"
@@ -144,6 +144,7 @@ msgstr "ć¢ć«ć¦ć³ćć®ććććÆćč§£é¤ćć¾ćć"
msgid "Account unmuted"
msgstr "ć¢ć«ć¦ć³ćć®ćć„ć¼ććč§£é¤ćć¾ćć"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -185,14 +186,22 @@ msgstr "詳瓰ćčæ½å "
msgid "Add details to report"
msgstr "ć¬ćć¼ćć«č©³ē“°ćčæ½å "
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "ćŖć³ćÆć«ć¼ććčæ½å "
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "ćŖć³ćÆć«ć¼ććčæ½å ļ¼"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "ꬔć®DNSć¬ć³ć¼ćććć”ć¤ć³ć«čæ½å ćć¦ćć ććļ¼"
@@ -316,7 +325,7 @@ msgstr "ć¢ććŖćć¹ćÆć¼ćć®čØå®"
msgid "App Passwords"
msgstr "ć¢ććŖćć¹ćÆć¼ć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "ć³ć³ćć³ćć®č¦åć«ē°č°ćē³ćē«ć¦ć"
@@ -344,15 +353,16 @@ msgstr "čęÆ"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "ć¢ććŖćć¹ćÆć¼ćć{name}ććę¬å½ć«åé¤ćć¾ććļ¼"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "ę¬å½ć«ćć®äøęøććē “ę£ćć¾ććļ¼"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "ę¬å½ć«ććććć§ććļ¼"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "ę¬å½ć«ććććć§ććļ¼ćććÆå
ć«ę»ćć¾ććć"
@@ -374,15 +384,15 @@ msgstr "čøč”ēć¾ććÆę§ēć§ćÆćŖććć¼ćć"
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "ę»ć"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "ę»ć"
@@ -430,7 +440,7 @@ msgstr "ćć®ćŖć¹ććććććÆ"
msgid "Blocked"
msgstr "ććććÆććć¦ćć¾ć"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "ććććÆäøć®ć¢ć«ć¦ć³ć"
@@ -489,7 +499,7 @@ msgstr "BlueskyćÆćććŖććÆć§ćć"
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "BlueskyćÆććå„å
ØćŖć³ćć„ććć£ć¼ćę§ēÆććććć«ęå¾
ē¶ć使ēØćć¾ććęå¾
ē¶ććęć”ć§ćŖćå “åćWaitlistć«ćē³ćč¾¼ćæććć ććØęå¾
ē¶ććéććć¾ćć"
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "BlueskyćÆćć°ć¢ć¦ćććć¦ć¼ć¶ć¼ć«ććŖćć®ćććć£ć¼ć«ćę稿ć蔨示ćć¾ćććä»ć®ć¢ććŖćÆćć®ćŖćÆćØć¹ćć«åæććŖćå “åćććć¾ćććć®čØå®ćÆććŖćć®ć¢ć«ć¦ć³ććéå
¬éć«ćććć®ć§ćÆććć¾ććć"
@@ -541,8 +551,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "č±ę°åćć¹ćć¼ć¹ććć¤ćć³ćć¢ć³ćć¼ć¹ć³ć¢ć®ćæć使ēØåÆč½ć§ććé·ććÆ4ęå仄äø32ęå仄äøć§ććåæ
č¦ćććć¾ćć"
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -556,7 +566,7 @@ msgstr "č±ę°åćć¹ćć¼ć¹ććć¤ćć³ćć¢ć³ćć¼ć¹ć³ć¢ć®ćæć
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "ćć£ć³ć»ć«"
@@ -715,7 +725,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "ćć¹ć¦ć®ć¹ćć¬ć¼ćøćć¼ćæććÆćŖć¢ļ¼ćć®å¾åčµ·åćć¾ćļ¼"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "ę¤ē“¢ćÆćØćŖććÆćŖć¢"
@@ -723,6 +733,11 @@ msgstr "ę¤ē“¢ćÆćØćŖććÆćŖć¢"
msgid "click here"
msgstr "ćć”ćććÆćŖććÆ"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr "ę°č±”"
@@ -753,11 +768,15 @@ msgstr "ē»åćéćć"
msgid "Close image viewer"
msgstr "ē»åćć„ć¼ć¢ćéćć"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "ććć²ć¼ć·ć§ć³ćććæć¼ćéćć"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "äøéØć®ććć²ć¼ć·ć§ć³ćć¼ćéćć"
@@ -765,7 +784,7 @@ msgstr "äøéØć®ććć²ć¼ć·ć§ć³ćć¼ćéćć"
msgid "Closes password update alert"
msgstr "ćć¹ćÆć¼ćę“ę°ć¢ć©ć¼ććéćć"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "ę稿ć®ē·Øéē»é¢ćéććäøęøććåé¤ćć"
@@ -798,7 +817,7 @@ msgstr "åęčØå®ćå®äŗćć¦ć¢ć«ć¦ć³ćć使ćå§ćć"
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "{MAX_GRAPHEME_LENGTH}ęåć¾ć§ć®ę稿ćä½ę"
@@ -862,7 +881,7 @@ msgstr "ę„ē¶äø..."
msgid "Contact support"
msgstr "ćµćć¼ćć«é£ēµ”"
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "ć³ć³ćć³ćć®ćć£ć«ćæćŖć³ć°"
@@ -928,7 +947,7 @@ msgstr "ćć«ććć¼ćøć§ć³ććÆćŖćććć¼ćć«ć³ćć¼ćć¾ćć
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "ćÆćŖćććć¼ćć«ć³ćć¼ćć¾ćć"
@@ -944,7 +963,7 @@ msgstr "ć³ćć¼"
msgid "Copy link to list"
msgstr "ćŖć¹ććøć®ćŖć³ćÆćć³ćć¼"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "ę稿ćøć®ćŖć³ćÆćć³ćć¼"
@@ -952,7 +971,7 @@ msgstr "ę稿ćøć®ćŖć³ćÆćć³ćć¼"
msgid "Copy link to profile"
msgstr "ćććć£ć¼ć«ćøć®ćŖć³ćÆćć³ćć¼"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "ę稿ć®ććć¹ććć³ćć¼"
@@ -1008,7 +1027,7 @@ msgstr "ä½ęč
ļ¼<0/>"
msgid "Created by you"
msgstr "ä½ęč
ļ¼ććŖć"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "ćµć ćć¤ć«ä»ćć®ć«ć¼ććä½ęćć¾ćććć®ć«ć¼ććÆę¬”ć®ć¢ćć¬ć¹ćøćŖć³ćÆćć¾ćļ¼{url}"
@@ -1089,11 +1108,11 @@ msgstr "ćć¤ć¢ć«ć¦ć³ććåé¤"
msgid "Delete My Accountā¦"
msgstr "ćć¤ć¢ć«ć¦ć³ććåé¤ā¦"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "ę稿ćåé¤"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "ćć®ę稿ćåé¤ćć¾ććļ¼"
@@ -1120,7 +1139,7 @@ msgstr "čŖ¬ę"
#~ msgid "Developer Tools"
#~ msgstr "éēŗč
ćć¼ć«"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "ćŖć«ćčØćććććØćÆćć£ćļ¼"
@@ -1128,15 +1147,15 @@ msgstr "ćŖć«ćčØćććććØćÆćć£ćļ¼"
msgid "Dim"
msgstr "ć°ć¬ć¼"
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "ē “ę£"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "äøęøććē “ę£"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "ć¢ććŖććć°ć¢ć¦ćććć¦ć¼ć¶ć¼ć«čŖåć®ć¢ć«ć¦ć³ćć蔨示ććŖćććć«ćć"
@@ -1215,7 +1234,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr "ćććććć¦ē»åćčæ½å ćć"
@@ -1287,6 +1306,7 @@ msgstr "ćććć£ć¼ć«ćē·Øé"
msgid "Edit Profile"
msgstr "ćććć£ć¼ć«ćē·Øé"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "äæåććććć£ć¼ććē·Øé"
@@ -1369,6 +1389,11 @@ msgstr "ćć£ć¼ćć®ēµćć"
msgid "Enter a name for this App Password"
msgstr "ćć®ć¢ććŖćć¹ćÆć¼ćć®ååćå
„å"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "確čŖć³ć¼ććå
„åćć¦ćć ćć"
@@ -1422,7 +1447,7 @@ msgstr "ć¦ć¼ć¶ć¼åćØćć¹ćÆć¼ććå
„åćć¦ćć ćć"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "ćØć©ć¼ļ¼"
@@ -1493,7 +1518,7 @@ msgstr "ć¢ććŖćć¹ćÆć¼ćć®ä½ęć«å¤±ęćć¾ććć"
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "ćŖć¹ćć®ä½ęć«å¤±ęćć¾ćććć¤ć³ćæć¼ććććøć®ę„ē¶ć確čŖć®äøćććäøåŗ¦ć試ććć ććć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "ę稿ć®åé¤ć«å¤±ęćć¾ćććććäøåŗ¦ć試ććć ććć"
@@ -1515,8 +1540,8 @@ msgid "Feed offline"
msgstr "ćć£ć¼ććÆćŖćć©ć¤ć³ć§ć"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "ćć£ć¼ćć®čØå®"
+#~ msgid "Feed Preferences"
+#~ msgstr "ćć£ć¼ćć®čØå®"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1564,11 +1589,11 @@ msgstr "ęå¾ć«"
msgid "Find accounts to follow"
msgstr "ćć©ćć¼ććć¢ć«ć¦ć³ććę¢ć"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Blueskyć§ć¦ć¼ć¶ć¼ćę¤ē“¢"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "å³å“ć®ę¤ē“¢ćć¼ć«ć§ć¦ć¼ć¶ć¼ćę¤ē“¢"
@@ -1673,6 +1698,7 @@ msgid "Following {0}"
msgstr "{0}ććć©ćć¼ćć¦ćć¾ć"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1712,7 +1738,7 @@ msgstr "ćć¹ćÆć¼ććåæćć"
msgid "Forgot Password"
msgstr "ćć¹ćÆć¼ććåæćć"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "<0/>ćć"
@@ -1745,7 +1771,7 @@ msgstr "ę»ć"
msgid "Go back to previous step"
msgstr "åć®ć¹ćććć«ę»ć"
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr "@{queryMaybeHandle}ćø"
@@ -1762,6 +1788,10 @@ msgstr "ꬔćø"
msgid "Handle"
msgstr "ćć³ćć«"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr "ä½ćåé”ćēŗēćć¾ćććļ¼"
@@ -1804,7 +1834,7 @@ msgctxt "action"
msgid "Hide"
msgstr "é蔨示"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "ę稿ćé蔨示"
@@ -1813,7 +1843,7 @@ msgstr "ę稿ćé蔨示"
msgid "Hide the content"
msgstr "ć³ć³ćć³ććé蔨示"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "ćć®ę稿ćé蔨示ć«ćć¾ććļ¼"
@@ -1975,7 +2005,7 @@ msgstr "ććŖćć®ćć¹ćÆć¼ććå
„å"
msgid "Input your user handle"
msgstr "ććŖćć®ć¦ć¼ć¶ć¼ćć³ćć«ćå
„å"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "ē”å¹ć¾ććÆćµćć¼ćććć¦ććŖćę稿ć®ć¬ć³ć¼ć"
@@ -2077,7 +2107,7 @@ msgstr "詳瓰"
msgid "Learn more about this warning"
msgstr "ćć®č¦åć®č©³ē“°"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Blueskyć§å
¬éććć¦ććå
容ćÆćć”ććåē
§ćć¦ćć ććć"
@@ -2161,7 +2191,7 @@ msgstr "ććŖćć®ę稿ććććććć¾ćć"
msgid "Likes"
msgstr "ććć"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "ćć®ę稿ćććććć"
@@ -2222,7 +2252,7 @@ msgstr "ę稿ćććć«ćć¼ć"
msgid "Load new notifications"
msgstr "ęę°ć®éē„ććć¼ć"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2252,7 +2282,7 @@ msgstr "ćć°ć¢ć¦ć"
#~ msgid "Logged-out users"
#~ msgstr "ćć°ć¢ć¦ćććć¦ć¼ć¶ć¼"
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "ćć°ć¢ć¦ćććć¦ć¼ć¶ć¼ććć®åÆč¦ę§"
@@ -2268,6 +2298,10 @@ msgstr "ćŖć¹ćć«ćŖćć¢ć«ć¦ć³ćć«ćć°ć¤ć³"
msgid "Make sure this is where you intend to go!"
msgstr "ęå³ććå “ęć§ććććØć確čŖćć¦ćć ććļ¼"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2289,7 +2323,7 @@ msgid "Mentioned users"
msgstr "ć”ć³ć·ć§ć³ćććć¦ć¼ć¶ć¼"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "ć”ćć„ć¼"
@@ -2302,7 +2336,7 @@ msgid "Message from server: {0}"
msgstr "ćµć¼ćć¼ććć®ć”ćć»ć¼ćøļ¼{0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2333,7 +2367,7 @@ msgstr "ć¢ćć¬ć¼ć·ć§ć³ćŖć¹ććä½ęćć¾ćć"
msgid "Moderation list updated"
msgstr "ć¢ćć¬ć¼ć·ć§ć³ćŖć¹ććę“ę°ćć¾ćć"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "ć¢ćć¬ć¼ć·ć§ć³ćŖć¹ć"
@@ -2360,7 +2394,7 @@ msgstr "ćć®ä»ć®ćć£ć¼ć"
msgid "More options"
msgstr "ćć®ä»ć®ćŖćć·ć§ć³"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "ćć®ć»ćć®ę稿ć®ćŖćć·ć§ć³"
@@ -2372,6 +2406,14 @@ msgstr "ćććć®ę°ćå¤ćé ć«čæäæ”ć蔨示"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "ć¢ć«ć¦ć³ćććć„ć¼ć"
@@ -2380,6 +2422,18 @@ msgstr "ć¢ć«ć¦ć³ćććć„ć¼ć"
msgid "Mute accounts"
msgstr "ć¢ć«ć¦ć³ćććć„ć¼ć"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "ćŖć¹ćććć„ć¼ć"
@@ -2392,15 +2446,27 @@ msgstr "ćććć®ć¢ć«ć¦ć³ćććć„ć¼ććć¾ććļ¼"
msgid "Mute this List"
msgstr "ćć®ćŖć¹ćććć„ć¼ć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "ć¹ć¬ććććć„ć¼ć"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "ćć„ć¼ćććć¦ćć¾ć"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "ćć„ć¼ćäøć®ć¢ć«ć¦ć³ć"
@@ -2413,6 +2479,10 @@ msgstr "ćć„ć¼ćäøć®ć¢ć«ć¦ć³ć"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "ćć„ć¼ćäøć®ć¢ć«ć¦ć³ćć®ę稿ćÆććć£ć¼ććéē„ććåćé¤ććć¾ćććć„ć¼ćć®čØå®ćÆå®å
Øć«éå
¬éć§ćć"
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "ćć„ć¼ćć®čØå®ćÆéå
¬éć§ćććć„ć¼ćäøć®ć¢ć«ć¦ć³ććÆććŖććØå¼ćē¶ćé¢ććććØćć§ćć¾ććććć®ć¢ć«ć¦ć³ćć®ę稿ćéē„ćåäæ”ććććØćÆć§ćć¾ććć"
@@ -2476,6 +2546,10 @@ msgstr "ćć©ććÆć¼ććć¼ćæćøć®ć¢ćÆć»ć¹ć失ćććØćÆććć¾
msgid "Never lose access to your followers or data."
msgstr "ćć©ććÆć¼ććć¼ćæćøć®ć¢ćÆć»ć¹ć失ćććØćÆććć¾ććć"
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2497,7 +2571,7 @@ msgstr "ę°ćććć¹ćÆć¼ć"
msgid "New Password"
msgstr "ę°ćććć¹ćÆć¼ć"
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "ę°ććę稿"
@@ -2586,8 +2660,8 @@ msgid "No results found for \"{query}\""
msgstr "ć{query}ćć®ę¤ē“¢ēµęćÆććć¾ćć"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "ć{query}ćć®ę¤ē“¢ēµęćÆććć¾ćć"
@@ -2617,7 +2691,7 @@ msgstr "ä»ćÆććŖć"
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
#~ msgstr "注čØļ¼BlueskyćÆćŖć¼ćć³ć§ćććŖććÆćŖććććÆć¼ćÆć§ććććć®čØå®ćęå¹ć«ćć¦ććć°ć¤ć³ćć¦ććć¦ć¼ć¶ć¼ćÆććŖćć®ćććć£ć¼ć«ćę稿ćå¶éćŖćé²č¦§ć§ćć¾ćććć®čØå®ćÆBlueskyć®ć¢ććŖććć³ć¦ć§ććµć¤ćäøć®ćæć§ć®ććŖćć®ć³ć³ćć³ćć®åÆč¦ę§ćå¶éćććć®ć§ććBlueskyć®ć³ć³ćć³ćć蔨示ćććµć¼ććć¼ćć£ć¼ć®ć¢ććŖćć¦ć§ććµć¤ććŖć©ćÆćć®čØå®ćå°éććŖćå “åćććććć°ć¢ć¦ćććć¦ć¼ć¶ć¼ć«åƾćććŖćć®ć³ć³ćć³ćć蔨示ćććåÆč½ę§ćććć¾ćć"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "注čØļ¼BlueskyćÆćŖć¼ćć³ć§ćććŖććÆćŖććććÆć¼ćÆć§ćććć®čØå®ćÆBlueskyć®ć¢ććŖććć³ć¦ć§ććµć¤ćäøć®ćæć§ć®ććŖćć®ć³ć³ćć³ćć®åÆč¦ę§ćå¶éćććć®ć§ćććä»ć®ć¢ććŖć§ćÆćć®čØå®ćå°éććŖćå “åćććć¾ććä»ć®ć¢ććŖćć¦ć§ććµć¤ćć§ćÆććć°ć¢ć¦ćććć¦ć¼ć¶ć¼ć«ććŖćć®ć³ć³ćć³ćć蔨示ćććå “åćććć¾ćć"
@@ -2655,7 +2729,7 @@ msgstr "å¤ćé ć«čæäæ”ć蔨示"
msgid "Onboarding reset"
msgstr "ćŖć³ćć¼ćć£ć³ć°ć®ćŖć»ćć"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "1ć¤ććććÆč¤ę°ć®ē»åć«ALTććć¹ććććć¾ććć"
@@ -2672,8 +2746,12 @@ msgstr "ćć£ćØļ¼"
msgid "Open"
msgstr "éććć¦ćć¾ć"
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "ēµµęåćå
„å"
@@ -2681,6 +2759,10 @@ msgstr "ēµµęåćå
„å"
msgid "Open links with in-app browser"
msgstr "ć¢ććŖå
ćć©ć¦ć¶ć¼ć§ćŖć³ćÆćéć"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "ććć²ć¼ć·ć§ć³ćéć"
@@ -2757,6 +2839,7 @@ msgstr "ć¢ćć¬ć¼ć·ć§ć³ć®čØå®ćéć"
msgid "Opens password reset form"
msgstr "ćć¹ćÆć¼ććŖć»ććć®ćć©ć¼ć ćéć"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "äæåććććć£ć¼ćć®ē·Øéē»é¢ćéć"
@@ -2941,7 +3024,7 @@ msgstr "ćć®ć³ć³ćć³ćć«åƾććč¦åćčŖ¤ć£ć¦é©ēØććććØę
msgid "Please Verify Your Email"
msgstr "ć”ć¼ć«ć¢ćć¬ć¹ć確čŖćć¦ćć ćć"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "ćŖć³ćÆć«ć¼ćććć¼ććććć¾ć§ćå¾
ć”ćć ćć"
@@ -2953,8 +3036,8 @@ msgstr "ęæę²»"
msgid "Porn"
msgstr "ćć«ć"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "ę稿"
@@ -2970,7 +3053,7 @@ msgstr "ę稿"
#~ msgid "Post"
#~ msgstr "ę稿"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "{0}ć«ććę稿"
@@ -2980,11 +3063,11 @@ msgstr "{0}ć«ććę稿"
msgid "Post by @{0}"
msgstr "@{0}ć«ććę稿"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "ę稿ćåé¤"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "ę稿ćé蔨示"
@@ -2996,14 +3079,22 @@ msgstr "ę稿ć®čØčŖ"
msgid "Post Languages"
msgstr "ę稿ć®čØčŖ"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "ę稿ćč¦ć¤ććć¾ćć"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "ę稿"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "é蔨示ć®ę稿"
@@ -3068,11 +3159,11 @@ msgstr "ć¦ć¼ć¶ć¼ćäøę¬ć§ćć„ć¼ćć¾ććÆććććÆćććå
Ž
msgid "Public, shareable lists which can drive feeds."
msgstr "ćć£ć¼ććØćć¦å©ēØć§ćććå
¬éćććå
±ęåÆč½ćŖćŖć¹ćć"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "ę稿ćå
Ž"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "čæäæ”ćå
Ž"
@@ -3110,6 +3201,7 @@ msgstr "ććććć®ćć£ć¼ć"
msgid "Recommended Users"
msgstr "ććććć®ć¦ć¼ć¶ć¼"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3147,6 +3239,10 @@ msgstr "ć¤ć”ć¼ćøćåé¤"
msgid "Remove image preview"
msgstr "ć¤ć”ć¼ćøćć¬ćć„ć¼ćåé¤"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "ćŖćć¹ććåé¤"
@@ -3181,7 +3277,7 @@ msgstr "čæäæ”"
msgid "Replies to this thread are disabled"
msgstr "ćć®ć¹ć¬ćććøć®čæäæ”ćÆć§ćć¾ćć"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "čæäæ”"
@@ -3191,7 +3287,7 @@ msgid "Reply Filters"
msgstr "čæäæ”ć®ćć£ć«ćæć¼"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "<0/>ć«čæäæ”"
@@ -3213,7 +3309,7 @@ msgid "Report List"
msgstr "ćŖć¹ććå ±å"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "ę稿ćå ±å"
@@ -3242,7 +3338,7 @@ msgstr "ćŖćć¹ćć¾ććÆå¼ēØ"
msgid "Reposted By"
msgstr "ćŖćć¹ćććć¦ć¼ć¶ć¼"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr "{0}ć«ćŖćć¹ćććć"
@@ -3250,7 +3346,7 @@ msgstr "{0}ć«ćŖćć¹ćććć"
#~ msgid "Reposted by {0})"
#~ msgstr "{0}ć«ćććŖćć¹ć"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "<0/>ć«ćććŖćć¹ć"
@@ -3258,7 +3354,7 @@ msgstr "<0/>ć«ćććŖćć¹ć"
msgid "reposted your post"
msgstr "ććŖćć®ę稿ćÆćŖćć¹ćććć¾ćć"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "ćć®ę稿ććŖćć¹ć"
@@ -3409,9 +3505,9 @@ msgstr "äøēŖäøć¾ć§ć¹ćÆćć¼ć«"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3421,11 +3517,19 @@ msgstr "äøēŖäøć¾ć§ć¹ćÆćć¼ć«"
msgid "Search"
msgstr "ę¤ē“¢"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr "ć{query}ććę¤ē“¢"
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/screens/Search/Search.tsx:390
#~ msgid "Search for posts and users."
#~ msgstr "ę稿ćØć¦ć¼ć¶ć¼ćę¤ē“¢ćć¾ćć"
@@ -3440,6 +3544,22 @@ msgstr "ć¦ć¼ć¶ć¼ćę¤ē“¢"
msgid "Security Step Required"
msgstr "åæ
č¦ćŖć»ćć„ćŖćć£ć®ęé "
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "ć¬ć¤ććč¦ć"
@@ -3657,7 +3777,7 @@ msgid "Share"
msgstr "å
±ę"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "å
±ę"
@@ -3690,9 +3810,9 @@ msgstr "{0}ć«ććåćč¾¼ćæć蔨示"
msgid "Show follows similar to {0}"
msgstr "{0}ć«ä¼¼ćććććć®ćć©ćć¼åč£ć蔨示"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "ććć«č”Øē¤ŗ"
@@ -3860,7 +3980,7 @@ msgstr "ć½ććć¦ć§ć¢éēŗ"
msgid "Something went wrong. Check your email and try again."
msgstr "ćŖćććć®åé”ćēŗēćć¾ćććć”ć¼ć«ć¢ćć¬ć¹ć確čŖććććäøåŗ¦ć試ććć ććć"
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "ē³ć訳ććć¾ććļ¼ć»ćć·ć§ć³ć®ęå¹ęéćåćć¾ćććććäøåŗ¦ćć°ć¤ć³ćć¦ćć ććć"
@@ -3926,7 +4046,7 @@ msgstr "ćć®ćŖć¹ćć«ē»é²"
#~ msgid "Subscribed"
#~ msgstr "ē»é²ęøćæ"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "ććććć®ćć©ćć¼"
@@ -3970,6 +4090,14 @@ msgstr "ć·ć¹ćć "
msgid "System log"
msgstr "ć·ć¹ćć ćć°"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "ćć¼ć«"
@@ -3993,6 +4121,10 @@ msgstr "ę”ä»¶"
msgid "Terms of Service"
msgstr "å©ēØč¦ē“"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -4018,7 +4150,7 @@ msgstr "čä½ęØ©ććŖć·ć¼ćÆ<0/>ć«ē§»åćć¾ćć"
msgid "The following steps will help customize your Bluesky experience."
msgstr "ꬔć®ęé ć§ććŖćć®Blueskyć§ć®ä½éØćć«ć¹ćæćć¤ćŗć§ćć¾ćć"
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "ę稿ćåé¤ćććåÆč½ę§ćććć¾ćć"
@@ -4200,7 +4332,7 @@ msgstr "ćć®ćŖć¹ććÆē©ŗć§ćļ¼"
msgid "This name is already in use"
msgstr "ćć®ååćÆćć§ć«ä½æēØäøć§ć"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "ćć®ę稿ćÆåé¤ććć¾ććć"
@@ -4224,7 +4356,11 @@ msgstr "ćć®ć¦ć¼ć¶ć¼ćÆćććŖćććć„ć¼ććć<0/>ćŖć¹ćć«
msgid "This warning is only available for posts with media attached."
msgstr "ćć®č¦åćÆćć”ćć£ć¢ćę·»ä»ććć¦ććę稿ć«ć®ćæä½æēØć§ćć¾ćć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "ćć®ę稿ćććŖćć®ćć£ć¼ćć«ććć¦é蔨示ć«ćć¾ćć"
@@ -4241,6 +4377,10 @@ msgstr "ć¹ć¬ććć¢ć¼ć"
msgid "Threads Preferences"
msgstr "ć¹ć¬ććć®čØå®"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "ćććććć¦ć³ććć°ć«"
@@ -4249,9 +4389,9 @@ msgstr "ćććććć¦ć³ććć°ć«"
msgid "Transformations"
msgstr "å¤ę"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "翻訳"
@@ -4320,15 +4460,24 @@ msgstr "ę®åæµćŖćććć¢ć«ć¦ć³ććä½ęććććć®č¦ä»¶ćęŗć
msgid "Unlike"
msgstr "ććććå¤ć"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "ćć„ć¼ććč§£é¤"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "ć¢ć«ć¦ć³ćć®ćć„ć¼ććč§£é¤"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "ć¹ć¬ććć®ćć„ć¼ććč§£é¤"
@@ -4533,6 +4682,10 @@ msgstr "ććŖćć®ćć©ćć¼äøć®ć¦ć¼ć¶ć¼ć®ę稿ćčŖćæēµććć¾
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr "Skygazeć«ćććFor Youććć£ć¼ććććććļ¼"
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr "ęć
ć®ćDiscoverććć£ć¼ććććććļ¼"
@@ -4561,7 +4714,11 @@ msgstr "ē§ćć”ćÆććŖććåå ćć¦ćććććØććØć¦ć愽ććæ
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "大å¤ē³ć訳ććć¾ćććććć®ćŖć¹ćć解決ć§ćć¾ććć§ćććććć§ććć®åé”ć解決ććŖćå “åćÆćä½ęč
ć®@{handleOrDid}ć¾ć§ćåćåćććć ććć"
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "大å¤ē³ć訳ććć¾ććććę¤ē“¢ćå®äŗć§ćć¾ććć§ćććę°åå¾ć«å試č”ćć¦ćć ććć"
@@ -4582,7 +4739,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "ćć®{collectionName}ć®åé”ćÆä½ć§ććļ¼"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "ęčæć©ćļ¼"
@@ -4603,11 +4760,11 @@ msgstr "čæäæ”ć§ććć¦ć¼ć¶ć¼"
msgid "Wide"
msgstr "ćÆć¤ć"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "ę稿ćęøć"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "čæäæ”ćęøć"
@@ -4676,7 +4833,7 @@ msgstr "äæåććććć£ć¼ććććć¾ććļ¼"
msgid "You don't have any saved feeds."
msgstr "äæåććććć£ć¼ććććć¾ććć"
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "ććŖććę稿č
ćććććÆćć¦ććććć¾ććÆę稿č
ć«ćć£ć¦ććŖććÆććććÆććć¦ćć¾ćć"
@@ -4716,6 +4873,10 @@ msgstr "ć¢ććŖćć¹ćÆć¼ććÆć¾ć ä½ęććć¦ćć¾ćććäøć®ć
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "ćć„ć¼ććć¦ććć¢ć«ć¦ć³ććÆć¾ć ććć¾ćććć¢ć«ć¦ć³ćććć„ć¼ćććć«ćÆććććć£ć¼ć«ć«ē§»åććć¢ć«ć¦ć³ćć”ćć„ć¼ćććć¢ć«ć¦ć³ćććć„ć¼ćććéøęćć¾ćć"
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "ęäŗŗåćć³ć³ćć³ććęå¹ć«ććć«ćÆć18ę³ä»„äøć§ććåæ
č¦ćććć¾ćć"
@@ -4724,11 +4885,11 @@ msgstr "ęäŗŗåćć³ć³ćć³ććęå¹ć«ććć«ćÆć18ę³ä»„äøć§ć
msgid "You must be 18 years or older to enable adult content"
msgstr "ęäŗŗåćć³ć³ćć³ććęå¹ć«ććć«ćÆć18ę³ä»„äøć§ććåæ
č¦ćććć¾ćć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "ćć仄éććć®ć¹ć¬ććć«é¢ććéē„ćåćåćććØćÆć§ććŖććŖćć¾ć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "ćć仄éććć®ć¹ć¬ććć«é¢ććéē„ćåćåćććØćć§ćć¾ć"
@@ -4818,11 +4979,15 @@ msgstr "ćć«ćć³ćć«ćÆ<0>@{0}0>ć«ćŖćć¾ć"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "ć¢ććŖćć¹ćÆć¼ćć使ēØćć¦ćć°ć¤ć³ćććØćęå¾
ć³ć¼ććÆé蔨示ć«ćŖćć¾ćć"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr "ćć¹ćÆć¼ćć®å¤ę“ćå®äŗćć¾ććļ¼"
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "ę稿ćå
¬éćć¾ćć"
@@ -4841,7 +5006,7 @@ msgstr "ććŖćć®ćććć£ć¼ć«"
#~ msgid "Your profile and posts will not be visible to people visiting the Bluesky app or website without having an account and being logged in."
#~ msgstr "ććŖćć®ćććć£ć¼ć«ćØę稿ćÆćć¢ć«ć¦ć³ććęć£ć¦ććććć°ć¤ć³ćć¦ććŖćē¶ę
ć§Blueskyć®ć¢ććŖć¾ććÆć¦ć§ććµć¤ćć訪åććäŗŗć
ć«ćÆč”Øē¤ŗććć¾ććć"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "čæäæ”ćå
¬éćć¾ćć"
diff --git a/src/locale/locales/ko/messages.po b/src/locale/locales/ko/messages.po
index 7ef971ac77..b70ba1694c 100644
--- a/src/locale/locales/ko/messages.po
+++ b/src/locale/locales/ko/messages.po
@@ -76,7 +76,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "ģ ė²ģ ģ ģ±ģ ģ¬ģ©ķ ģ ģģµėė¤. ģ±ģ ź³ģ ģ¬ģ©ķė ¤ė©“ ģ
ė°ģ“ķøķģøģ."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "ķģ ė§ķ¬ ė° ģ¤ģ ģ¼ė” ģ“ėķ©ėė¤"
@@ -127,6 +127,7 @@ msgstr "ź³ģ ģ°ØėØ ķ“ģ ėØ"
msgid "Account unmuted"
msgstr "ź³ģ ģøė®¤ķøėØ"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -168,14 +169,22 @@ msgstr "ģøė¶ ģ 볓 ģ¶ź°"
msgid "Add details to report"
msgstr "ģ ź³ ģøė¶ ģ 볓 ģ¶ź°"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "ė§ķ¬ 칓ė ģ¶ź°"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "ė§ķ¬ 칓ė ģ¶ź°:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "ėė©ģøģ ė¤ģ DNS ė ģ½ė넼 ģ¶ź°ķģøģ:"
@@ -295,7 +304,7 @@ msgstr "ģ± ė¹ė°ė²ķø ģ¤ģ "
msgid "App Passwords"
msgstr "ģ± ė¹ė°ė²ķø"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "ģ½ķ
ģø ź²½ź³ ģ“ģģ ģ²"
@@ -319,15 +328,16 @@ msgstr "ėŖØģ"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "ģ± ė¹ė°ė²ķø \"{name}\"ģ(넼) ģģ ķģź² ģµėź¹?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "ģ“ ģ“ģģ ģģ ķģź² ģµėź¹?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "ģ ė§ģøź°ģ?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "ģ ė§ģøź°ģ? ėė릓 ģ ģģµėė¤."
@@ -349,15 +359,15 @@ msgstr "ģ ģ ģ ģ“ģ§ ģź±°ė ģģ ģ ģø ė
øģ¶."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "ė¤ė”"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "ė¤ė”"
@@ -405,7 +415,7 @@ msgstr "ģ“ ė¦¬ģ¤ķø ģ°ØėØ"
msgid "Blocked"
msgstr "ģ°ØėØėØ"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "ģ°ØėØķ ź³ģ "
@@ -464,7 +474,7 @@ msgstr "Blueskyė ź³µź°ģ ģ
ėė¤."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Blueskyė ė ź±“ź°ķ 커뮤ėķ°ė„¼ 구ģ¶ķźø° ģķ“ ģ“ė ė°©ģģ ģ¬ģ©ķ©ėė¤. ģ“ėķ“ ģ¤ ģ¬ėģ“ ģė ź²½ģ° ėźø°ģ ėŖ
ėØģ ė±ė”ķė©“ ź³§ ģ“ė넼 ė³“ė“ź² ģµėė¤."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "ė”ź·øģģķ ģ¬ģ©ģģź² ė“ ķė”ķź³¼ ź²ģ물ģ ķģķģ§ ģģµėė¤. ė¤ė„ø ģ±ģģė ģ“ ģ¤ģ ģ ė°ė„“ģ§ ģģ ģ ģģµėė¤. ė“ ź³ģ ģ ė¹ź³µź°ė” ģ ķķģ§ė ģģµėė¤."
@@ -516,8 +526,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "źøģ, ģ«ģ, 공백, ėģ, ė°ģ¤ė§ ķ¬ķØķ ģ ģģµėė¤. źøøģ“ė 4ģ ģ“ģģ“ģ“ģ¼ ķź³ 32ģ넼 ėģ§ ģģģ¼ ķ©ėė¤."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -531,7 +541,7 @@ msgstr "źøģ, ģ«ģ, 공백, ėģ, ė°ģ¤ė§ ķ¬ķØķ ģ ģģµėė¤.
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "ģ·Øģ"
@@ -678,7 +688,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "ėŖØė ģ¤ķ ė¦¬ģ§ ė°ģ“ķ° ģ§ģ°źø° (ģ“ķ ė¤ģ ģģ)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "ź²ģģ“ ģ§ģ°źø°"
@@ -686,6 +696,11 @@ msgstr "ź²ģģ“ ģ§ģ°źø°"
msgid "click here"
msgstr "ģ“ź³³ģ ķ“ė¦"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr "źø°ķ"
@@ -716,11 +731,15 @@ msgstr "ģ“ėÆøģ§ ė«źø°"
msgid "Close image viewer"
msgstr "ģ“ėÆøģ§ ė·°ģ“ ė«źø°"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "ķģ ķøķ° ė«źø°"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "ķėØ ķģ ė§ė넼 ė«ģµėė¤"
@@ -728,7 +747,7 @@ msgstr "ķėØ ķģ ė§ė넼 ė«ģµėė¤"
msgid "Closes password update alert"
msgstr "ė¹ė°ė²ķø ė³ź²½ ģ림ģ ė«ģµėė¤"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "ź²ģ물 ģģ± ģģ넼 ė«ź³ ź²ģ물 ģ“ģģ ģģ ķ©ėė¤"
@@ -761,7 +780,7 @@ msgstr "ģØė³“ė© ģė£ ķ ź³ģ ģ¬ģ© ģģ"
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "ģµė {MAX_GRAPHEME_LENGTH}ģ źøøģ“ź¹ģ§ źøģ ģģ±ķ ģ ģģµėė¤"
@@ -825,7 +844,7 @@ msgstr "ģ°ź²° ģ¤ā¦"
msgid "Contact support"
msgstr "ģ§ģģ ģ°ė½ķźø°"
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "ģ½ķ
ģø ķķ°ė§"
@@ -891,7 +910,7 @@ msgstr "ė¹ė ė²ģ ķ“립볓ėģ ė³µģ¬ėØ"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "ķ“립볓ėģ ė³µģ¬ėØ"
@@ -907,7 +926,7 @@ msgstr "ė³µģ¬"
msgid "Copy link to list"
msgstr "리ģ¤ķø ė§ķ¬ ė³µģ¬"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "ź²ģ물 ė§ķ¬ ė³µģ¬"
@@ -915,7 +934,7 @@ msgstr "ź²ģ물 ė§ķ¬ ė³µģ¬"
msgid "Copy link to profile"
msgstr "ķė”ķ ė§ķ¬ ė³µģ¬"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "ź²ģ물 ķ
ģ¤ķø ė³µģ¬"
@@ -971,7 +990,7 @@ msgstr "<0/> ėģ“ ė§ė¦"
msgid "Created by you"
msgstr "ė“ź° ė§ė¦"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "미리볓기 ģ“ėÆøģ§ź° ģė 칓ė넼 ė§ėėė¤. ģ¹“ėź° {url}(ģ¼)ė” ģ°ź²°ė©ėė¤"
@@ -1048,11 +1067,11 @@ msgstr "ė“ ź³ģ ģģ "
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "ź²ģ물 ģģ "
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "ģ“ ź²ģ물ģ ģģ ķģź² ģµėź¹?"
@@ -1075,7 +1094,7 @@ msgstr "ģ¤ėŖ
"
#~ msgid "Developer Tools"
#~ msgstr "ź°ė°ģ ėźµ¬"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "ķź³ ģ¶ģ ė§ģ“ ģėģ?"
@@ -1083,15 +1102,15 @@ msgstr "ķź³ ģ¶ģ ė§ģ“ ģėģ?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "ģģ "
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "ģ“ģ ģģ "
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "ģ±ģ“ ė”ź·øģģķ ģ¬ģ©ģģź² ė“ ź³ģ ģ ķģķģ§ ģėė” ģ¤ģ ķźø°"
@@ -1170,7 +1189,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr "ėė”ķģ¬ ģ“ėÆøģ§ ģ¶ź°"
@@ -1242,6 +1261,7 @@ msgstr "ķė”ķ ķøģ§"
msgid "Edit Profile"
msgstr "ķė”ķ ķøģ§"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "ģ ģ„ė ķ¼ė ķøģ§"
@@ -1324,6 +1344,11 @@ msgstr "ķ¼ė ė"
msgid "Enter a name for this App Password"
msgstr "ģ“ ģ± ė¹ė°ė²ķøģ ģ“ė¦ģ ģ
ė „ķģøģ"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "ķģø ģ½ė ģ
ė „"
@@ -1373,7 +1398,7 @@ msgstr "ģ¬ģ©ģ ģ“ė¦ ė° ė¹ė°ė²ķø ģ
ė „"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "ģ¤ė„:"
@@ -1444,7 +1469,7 @@ msgstr "ģ± ė¹ė°ė²ķøė„¼ ė§ė¤ģ§ ėŖ»ķģµėė¤."
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "리ģ¤ķøė„¼ ė§ė¤ģ§ ėŖ»ķģµėė¤. ģøķ°ė· ģ°ź²°ģ ķģøķ ķ ė¤ģ ģėķģøģ."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "ź²ģ물ģ ģģ ķģ§ ėŖ»ķģµėė¤. ė¤ģ ģėķ“ ģ£¼ģøģ"
@@ -1466,8 +1491,8 @@ msgid "Feed offline"
msgstr "ķ¼ė ģ¤ķė¼ģø"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "ķ¼ė ģ¤ģ "
+#~ msgid "Feed Preferences"
+#~ msgstr "ķ¼ė ģ¤ģ "
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1507,11 +1532,11 @@ msgstr "ė§ė¬“리 ģ¤"
msgid "Find accounts to follow"
msgstr "ķė”ģ°ķ ź³ģ ģ°¾ģ볓기"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Blueskyģģ ģ¬ģ©ģ 찾기"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "ģ¤ė„øģŖ½ģ ź²ģ ėźµ¬ė” ģ¬ģ©ģ 찾기"
@@ -1608,6 +1633,7 @@ msgid "Following {0}"
msgstr "{0} ķė”ģ° ģ¤"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1647,7 +1673,7 @@ msgstr "ė¹ė°ė²ķø ė¶ģ¤"
msgid "Forgot Password"
msgstr "ė¹ė°ė²ķø ė¶ģ¤"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "<0/>ģģ"
@@ -1680,7 +1706,7 @@ msgstr "ė¤ė”"
msgid "Go back to previous step"
msgstr "ģ“ģ ėØź³ė” ėģź°źø°"
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr "@{queryMaybeHandle}(ģ¼)ė” ģ“ė"
@@ -1697,6 +1723,10 @@ msgstr "ė¤ģ"
msgid "Handle"
msgstr "ķøė¤"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr "ė¬øģ ź° ģėģ?"
@@ -1735,7 +1765,7 @@ msgctxt "action"
msgid "Hide"
msgstr "ģØźø°źø°"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "ź²ģ물 ģØźø°źø°"
@@ -1744,7 +1774,7 @@ msgstr "ź²ģ물 ģØźø°źø°"
msgid "Hide the content"
msgstr "ģ½ķ
ģø ģØźø°źø°"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "ģ“ ź²ģ물ģ ģØźø°ģź² ģµėź¹?"
@@ -1893,7 +1923,7 @@ msgstr "ė¹ė°ė²ķøė„¼ ģ
ė „ķ©ėė¤"
msgid "Input your user handle"
msgstr "ģ¬ģ©ģ ķøė¤ģ ģ
ė „ķ©ėė¤"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "ģ ķØķģ§ ģź±°ė ģ§ģėģ§ ģė ź²ģ물 źø°ė”"
@@ -1995,7 +2025,7 @@ msgstr "ė ģģ볓기"
msgid "Learn more about this warning"
msgstr "ģ“ ź²½ź³ ģ ėķ“ ė ģģ볓기"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Blueskyģģ ź³µź°ėė ķėŖ©ģ ėķ“ ģģøķ ģģ볓ģøģ."
@@ -2071,7 +2101,7 @@ msgstr "ėģ“ ė“ ź²ģ물ģ ģ¢ģķ©ėė¤"
msgid "Likes"
msgstr "ģ¢ģģ"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "ģ“ ź²ģ물ģ ģ¢ģģ ķģķ©ėė¤"
@@ -2128,7 +2158,7 @@ msgstr "ė ė§ģ ź²ģ물 ė¶ė¬ģ¤źø°"
msgid "Load new notifications"
msgstr "ģ ģ림 ė¶ė¬ģ¤źø°"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2154,7 +2184,7 @@ msgstr "ė”ź·ø"
msgid "Log out"
msgstr "ė”ź·øģģ"
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "ė”ź·øģģ ķģ"
@@ -2166,6 +2196,10 @@ msgstr "ėŖ©ė”ģ ģė ź³ģ ģ¼ė” ė”ź·øģø"
msgid "Make sure this is where you intend to go!"
msgstr "ģ“ź³³ģ“ ė¹ģ ģ“ ź°ź³ ģ ķė ź³³ģøģ§ ķģøķģøģ!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2187,7 +2221,7 @@ msgid "Mentioned users"
msgstr "ė©ģ
ķ ģ¬ģ©ģ"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "ė©ė“"
@@ -2196,7 +2230,7 @@ msgid "Message from server: {0}"
msgstr "ģė²ģģ ė³“ėø ė©ģģ§: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2227,7 +2261,7 @@ msgstr "ź²ķ 리ģ¤ķø ģģ±ėØ"
msgid "Moderation list updated"
msgstr "ź²ķ 리ģ¤ķø ģ
ė°ģ“ķøėØ"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "ź²ķ 리ģ¤ķø"
@@ -2254,7 +2288,7 @@ msgstr "ķ¼ė ė 볓기"
msgid "More options"
msgstr "ģµģ
ė 볓기"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "ź²ģ물 ģµģ
ė 볓기"
@@ -2266,6 +2300,14 @@ msgstr "ģ¢ģģ ė§ģ ģ"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "ź³ģ 뮤ķø"
@@ -2274,6 +2316,18 @@ msgstr "ź³ģ 뮤ķø"
msgid "Mute accounts"
msgstr "ź³ģ 뮤ķø"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "리ģ¤ķø 뮤ķø"
@@ -2286,15 +2340,27 @@ msgstr "ģ“ ź³ģ ė¤ģ 뮤ķøķģź² ģµėź¹?"
msgid "Mute this List"
msgstr "ģ“ ė¦¬ģ¤ķø 뮤ķø"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "ģ¤ė ė 뮤ķø"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "뮤ķøėØ"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "뮤ķøķ ź³ģ "
@@ -2307,6 +2373,10 @@ msgstr "뮤ķøķ ź³ģ "
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "ź³ģ ģ 뮤ķøķė©“ ķ¼ėģ ģ림ģģ ķ“ė¹ ź³ģ ģ ź²ģė¬¼ģ“ ģ¬ė¼ģ§ėė¤. ė®¤ķø ėŖ©ė”ģ ģģ ķ ė¹ź³µź°ė” ģ ģ§ė©ėė¤."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "ė®¤ķø ėŖ©ė”ģ ė¹ź³µź°ģ
ėė¤. 뮤ķøķ ź³ģ ģ ėģ ģķøģģ©ķ ģ ģģ§ė§ ķ“ė¹ ź³ģ ģ ź²ģ물ģ 볓거ė ķ“ė¹ ź³ģ ģ¼ė”ė¶ķ° ģ림ģ ė°ģ ģ ģģµėė¤."
@@ -2370,6 +2440,10 @@ msgstr "ķė”ģģ ė°ģ“ķ°ģ ėķ ģ ź·¼ ź¶ķģ ģģ§ ģģµėė¤."
msgid "Never lose access to your followers or data."
msgstr "ķė”ģ ėė ė°ģ“ķ°ģ ėķ ģ ź·¼ ź¶ķģ ģģ§ ģģµėė¤."
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2391,7 +2465,7 @@ msgstr "ģ ė¹ė°ė²ķø"
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "ģ ź²ģ물"
@@ -2476,8 +2550,8 @@ msgid "No results found for \"{query}\""
msgstr "\"{query}\"ģ ėķ ź²°ź³¼ė„¼ ģ°¾ģ ģ ģģµėė¤"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "{query}ģ ėķ ź²°ź³¼ė„¼ ģ°¾ģ ģ ģģµėė¤"
@@ -2503,7 +2577,7 @@ msgstr "ģ°¾ģ ģ ģģ"
msgid "Not right now"
msgstr "ėģ¤ģ ķźø°"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "ģ°øź³ : Blueskyė ź°ė°©ķ ź³µź° ė¤ķøģķ¬ģ
ėė¤. ģ“ ģ¤ģ ģ Bluesky ģ±ź³¼ ģ¹ģ¬ģ“ķøģģė§ ė“ ģ½ķ
ģø ź° ķģėė ź²ģ ģ ķķė©°, ė¤ė„ø ģ±ģģė ģ“ ģ¤ģ ģ ģ¤ģķģ§ ģģ ģ ģģµėė¤. ė¤ė„ø ģ±ź³¼ ģ¹ģ¬ģ“ķøģģė ė”ź·øģģķ ģ¬ģ©ģģź² ė“ ģ½ķ
ģø ź° ź³ģ ķģė ģ ģģµėė¤."
@@ -2541,7 +2615,7 @@ msgstr "ģ¤ėė ģ"
msgid "Onboarding reset"
msgstr "ģØė³“ė© ģ¬ģ¤ģ "
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "ķė ģ“ģģ ģ“미ģ§ģ ė첓 ķ
ģ¤ķøź° ėė½ėģģµėė¤."
@@ -2558,8 +2632,12 @@ msgstr "ģ“ė°!"
msgid "Open"
msgstr "ź³µź°ģ±"
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "ģ“ėŖØķ°ģ½ ģ ķźø° ģ“źø°"
@@ -2567,6 +2645,10 @@ msgstr "ģ“ėŖØķ°ģ½ ģ ķźø° ģ“źø°"
msgid "Open links with in-app browser"
msgstr "ė§ķ¬ė„¼ ģøģ± ėøė¼ģ°ģ ė” ģ½ėė¤"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "ė“ė¹ź²ģ“ģ
ģ“źø°"
@@ -2643,6 +2725,7 @@ msgstr "ź²ķ ģ¤ģ ģ ģ½ėė¤"
msgid "Opens password reset form"
msgstr "ė¹ė°ė²ķø ģ¬ģ¤ģ ģģģ ģ½ėė¤"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "ģ ģ„ė ķ¼ė넼 ķøģ§ķ ģ ģė ķė©“ģ ģ½ėė¤"
@@ -2818,7 +2901,7 @@ msgstr "ģ“ ģ½ķ
ģø ź²½ź³ ź° ģėŖ» ģ ģ©ėģė¤ź³ ģź°ķė ģ“ģ 넼
msgid "Please Verify Your Email"
msgstr "ģ“ė©ģ¼ ģøģ¦ķźø°"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "ė§ķ¬ 칓ė넼 ģģ ķ ė¶ė¬ģ¬ ėź¹ģ§ źø°ė¤ė ¤ģ£¼ģøģ"
@@ -2830,8 +2913,8 @@ msgstr "ģ ģ¹"
msgid "Porn"
msgstr "ķ¬ė„“ė
ø"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "ź²ģķźø°"
@@ -2841,7 +2924,7 @@ msgctxt "description"
msgid "Post"
msgstr "ź²ģ물"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "{0} ėģ ź²ģ물"
@@ -2851,11 +2934,11 @@ msgstr "{0} ėģ ź²ģ물"
msgid "Post by @{0}"
msgstr "@{0} ėģ ź²ģ물"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "ź²ģ물 ģģ ėØ"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "ź²ģ물 ģØź¹"
@@ -2867,14 +2950,22 @@ msgstr "ź²ģ물 ģøģ“"
msgid "Post Languages"
msgstr "ź²ģ물 ģøģ“"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "ź²ģ물ģ ģ°¾ģ ģ ģģ"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "ź²ģ물"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "ź²ģ물 ģØź²Øģ§"
@@ -2939,11 +3030,11 @@ msgstr "ģ¼ź“ 뮤ķøķź±°ė ģ°ØėØķ ģ ģė ź³µź°ģ ģ“ź³ ź³µģ ź°
msgid "Public, shareable lists which can drive feeds."
msgstr "ķ¼ė넼 ķģķ ģ ģė ź³µź°ģ ģ“ź³ ź³µģ ź°ė„ķ ėŖ©ė”ģ
ėė¤."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "ź²ģ물 ź²ģķźø°"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "ėµźø ź²ģķźø°"
@@ -2977,6 +3068,7 @@ msgstr "ģ¶ģ² ķ¼ė"
msgid "Recommended Users"
msgstr "ģ¶ģ² ģ¬ģ©ģ"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3014,6 +3106,10 @@ msgstr "ģ“ėÆøģ§ ģ ź±°"
msgid "Remove image preview"
msgstr "ģ“ėÆøģ§ ėÆøė¦¬ė³“źø° ģ ź±°"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "ģ¬ź²ģ넼 ģ·Øģķ©ėė¤"
@@ -3048,7 +3144,7 @@ msgstr "ėµźø"
msgid "Replies to this thread are disabled"
msgstr "ģ“ ģ¤ė ėģ ėķ ėµźøģ“ ė¹ķģ±ķė©ėė¤."
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "ėµźø"
@@ -3058,7 +3154,7 @@ msgid "Reply Filters"
msgstr "ėµźø ķķ°"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "<0/> ėģź² 볓ė“ė ėµźø"
@@ -3080,7 +3176,7 @@ msgid "Report List"
msgstr "리ģ¤ķø ģ ź³ "
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "ź²ģ물 ģ ź³ "
@@ -3105,11 +3201,11 @@ msgstr "ģ¬ź²ģ ėė ź²ģ물 ģøģ©"
msgid "Reposted By"
msgstr "ģ¬ź²ģķ ģ¬ģ©ģ"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr "{0} ėģ“ ģ¬ź²ģķØ"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "<0/> ėģ“ ģ¬ź²ģķØ"
@@ -3117,7 +3213,7 @@ msgstr "<0/> ėģ“ ģ¬ź²ģķØ"
msgid "reposted your post"
msgstr "ėģ“ ė“ ź²ģ물ģ ģ¬ź²ģķģµėė¤"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "ģ“ ź²ģ물ģ ģ¬ź²ģ"
@@ -3268,9 +3364,9 @@ msgstr "ė§Ø ģė” ģ¤ķ¬ė”¤"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3280,11 +3376,19 @@ msgstr "ė§Ø ģė” ģ¤ķ¬ė”¤"
msgid "Search"
msgstr "ź²ģ"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr "\"{query}\"ģ ėķ ź²ģ ź²°ź³¼"
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3295,6 +3399,22 @@ msgstr "ģ¬ģ©ģ ź²ģķźø°"
msgid "Security Step Required"
msgstr "볓ģ ėØź³ ķģ"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "ģ“ ź°ģ“ė"
@@ -3500,7 +3620,7 @@ msgid "Share"
msgstr "ź³µģ "
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "ź³µģ "
@@ -3533,9 +3653,9 @@ msgstr "{0} ģė² ė ķģ"
msgid "Show follows similar to {0}"
msgstr "{0} ėź³¼ ė¹ģ·ķ ķė”ģ° ķģ"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "ė 볓기"
@@ -3703,7 +3823,7 @@ msgstr "ģķķøģØģ“ ź°ė°"
msgid "Something went wrong. Check your email and try again."
msgstr "ė¬øģ ź° ė°ģķģµėė¤. ģ“ė©ģ¼ģ ķģøķ ķ ė¤ģ ģėķģøģ."
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "ģ£ģ”ķ©ėė¤. ģøģ
ģ“ ė§ė£ėģģµėė¤. ė¤ģ ė”ź·øģøķ“ 주ģøģ."
@@ -3761,7 +3881,7 @@ msgstr "{0} ķ¼ė 구ė
ķźø°"
msgid "Subscribe to this list"
msgstr "ģ“ ė¦¬ģ¤ķø 구ė
ķźø°"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "ķė”ģ° ģ¶ģ²"
@@ -3805,6 +3925,14 @@ msgstr "ģģ¤ķ
"
msgid "System log"
msgstr "ģģ¤ķ
ė”ź·ø"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "ģøė”"
@@ -3828,6 +3956,10 @@ msgstr "ģ“ģ©ģ½ź“"
msgid "Terms of Service"
msgstr "ģė¹ģ¤ ģ“ģ©ģ½ź“"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3853,7 +3985,7 @@ msgstr "ģ ģź¶ ģ ģ±
ģ <0/>(ģ¼)ė” ģ“ėķģµėė¤"
msgid "The following steps will help customize your Bluesky experience."
msgstr "ė¤ģ ėØź³ė Bluesky ķź²½ģ ė§ģ¶¤ ģ¤ģ ķė ė° ėģģ“ ė©ėė¤."
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "ź²ģė¬¼ģ“ ģģ ėģģ ģ ģģµėė¤."
@@ -4019,7 +4151,7 @@ msgstr "ģ“ ė¦¬ģ¤ķøė ė¹ģ“ ģģµėė¤."
msgid "This name is already in use"
msgstr "ģ“ ģ“ė¦ģ ģ“미 ģ¬ģ© ģ¤ģ
ėė¤"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "ģ“ ź²ģ물ģ ģģ ėģģµėė¤."
@@ -4043,7 +4175,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "ģ“ ź²½ź³ ė 미ėģ“ź° 첨ė¶ė ź²ģ물ģė§ ģ¬ģ©ķ ģ ģģµėė¤."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "ķ¼ėģģ ģ“ ź²ģ물ģ ģØź¹ėė¤."
@@ -4060,6 +4196,10 @@ msgstr "ģ¤ė ė ėŖØė"
msgid "Threads Preferences"
msgstr "ģ¤ė ė ģ¤ģ "
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "ėė”ė¤ģ“ ģ“źø° ė° ė«źø°"
@@ -4068,9 +4208,9 @@ msgstr "ėė”ė¤ģ“ ģ“źø° ė° ė«źø°"
msgid "Transformations"
msgstr "ė³ķ"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "ė²ģ"
@@ -4135,15 +4275,24 @@ msgstr "ģģ½ģ§ė§ ź³ģ ģ ė§ė¤ ģ ģė ģź±“ģ ģ¶©ģ”±ķģ§ ėŖ»ķ
msgid "Unlike"
msgstr "ģ¢ģģ ģ·Øģ"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "ģøė®¤ķø"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "ź³ģ ģøė®¤ķø"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "ģ¤ė ė ģøė®¤ķø"
@@ -4340,6 +4489,10 @@ msgstr "ģ¦ź±°ģ“ ģź° ėģźø° ė°ėėė¤. Blueskyģ ė¤ģ ķ¹ģ§ģ źø°
msgid "We ran out of posts from your follows. Here's the latest from <0/>."
msgstr "ķė”ģ°ķ ģ¬ģ©ģģ ź²ģė¬¼ģ“ ė¶ģ”±ķ©ėė¤. ėģ <0/>ģ ģµģ ź²ģ물ģ ķģķ©ėė¤."
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr "\"Discover\" ķ¼ė넼 ź¶ģ„ķ©ėė¤:"
@@ -4368,7 +4521,11 @@ msgstr "ė¹ģ ź³¼ ķØź»ķź² ėģ“ ģ ė§ źø°ģė¤ģ!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "ģ£ģ”ķģ§ė§ ģ“ ė¦¬ģ¤ķøė„¼ ė¶ė¬ģ¬ ģ ģģµėė¤. ģ“ ė¬øģ ź° ź³ģėė©“ 리ģ¤ķø ģģ±ģģø @{handleOrDid}ģź² 문ģķģøģ."
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "ģ£ģ”ķģ§ė§ ź²ģģ ģė£ķ ģ ģģµėė¤. ėŖ ė¶ ķģ ė¤ģ ģėķ“ ģ£¼ģøģ."
@@ -4389,7 +4546,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "ģ“ {collectionName}ģ ģ“ė¤ ė¬øģ ź° ģėģ?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "ė¬“ģØ ģ¼ģ“ ģ¼ģ“ėź³ ģėģ?"
@@ -4410,11 +4567,11 @@ msgstr "ėµźøģ ė¬ ģ ģė ģ¬ė"
msgid "Wide"
msgstr "ź°ė”"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "ź²ģ물 ģģ±"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "ėµźø ģģ±ķźø°"
@@ -4471,7 +4628,7 @@ msgstr "ģ ģ„ė ķ¼ėź° ģģµėė¤!"
msgid "You don't have any saved feeds."
msgstr "ģ ģ„ė ķ¼ėź° ģģµėė¤."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "ģģ±ģ넼 ģ°ØėØķź±°ė ģģ±ģź° ė넼 ģ°ØėØķģµėė¤."
@@ -4511,6 +4668,10 @@ msgstr "ģģ§ ģ± ė¹ė°ė²ķøė„¼ ģģ±ķģ§ ģģģµėė¤. ģė ė²ķ¼
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "ģģ§ ģ“ė¤ ź³ģ ė 뮤ķøķģ§ ģģģµėė¤. ź³ģ ģ 뮤ķøķė ¤ė©“ ķ“ė¹ ź³ģ ģ ķė”ķė” ģ“ėķģ¬ ź³ģ ė©ė“ģģ \"ź³ģ 뮤ķø\"넼 ģ ķķģøģ."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "ģ±ģø ģ½ķ
ģø ė„¼ ķģ±ķķė ¤ė©“ 18ģø ģ“ģģ“ģ“ģ¼ ķ©ėė¤."
@@ -4519,11 +4680,11 @@ msgstr "ģ±ģø ģ½ķ
ģø ė„¼ ķģ±ķķė ¤ė©“ 18ģø ģ“ģģ“ģ“ģ¼ ķ©ėė¤."
msgid "You must be 18 years or older to enable adult content"
msgstr "ģ±ģø ģ½ķ
ģø ė„¼ ģ¬ģ©ķė ¤ė©“ ė§ 18ģø ģ“ģģ“ģ“ģ¼ ķ©ėė¤."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "ģ“ ģ¤ė ėģ ėķ ģ림ģ ė ģ“ģ ė°ģ§ ģģµėė¤"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "ģ“ģ ģ“ ģ¤ė ėģ ėķ ģ림ģ ė°ģµėė¤"
@@ -4609,11 +4770,15 @@ msgstr "ė“ ģ 첓 ķøė¤: <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "ģ± ė¹ė°ė²ķøė„¼ ģ¬ģ©ķģ¬ ė”ź·øģøķė©“ ģ“ė ģ½ėź° ģØź²Øģ§ėė¤"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "ź²ģė¬¼ģ ź²ģķģµėė¤"
@@ -4628,7 +4793,7 @@ msgstr "ź²ģ물, ģ¢ģģ, ģ°ØėØ ėŖ©ė”ģ ź³µź°ė©ėė¤. ė®¤ķø ėŖ©ė”ģ
msgid "Your profile"
msgstr "ė“ ķė”ķ"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "ė“ ėµźøģ ź²ģķģµėė¤"
diff --git a/src/locale/locales/pt-BR/messages.po b/src/locale/locales/pt-BR/messages.po
index 9178214dd4..ff5d7e55dc 100644
--- a/src/locale/locales/pt-BR/messages.po
+++ b/src/locale/locales/pt-BR/messages.po
@@ -76,7 +76,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "Uma nova versĆ£o do aplicativo estĆ” disponĆvel. Por favor, atualize para continuar usando o aplicativo."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "Acessar links de navegação e configurações"
@@ -127,6 +127,7 @@ msgstr "Conta desbloqueada"
msgid "Account unmuted"
msgstr "Conta dessilenciada"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -168,14 +169,22 @@ msgstr "Adicionar detalhes"
msgid "Add details to report"
msgstr "Adicionar detalhes Ć denĆŗncia"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "Adicionar prƩvia de link"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "Adicionar prƩvia de link:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "Adicione o seguinte registro DNS ao seu domĆnio:"
@@ -299,7 +308,7 @@ msgstr "ConfiguraƧƵes de Senha de Aplicativo"
msgid "App Passwords"
msgstr "Senhas de Aplicativos"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "Contestar aviso de conteĆŗdo"
@@ -323,15 +332,16 @@ msgstr "AparĆŖncia"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "Tem certeza de que deseja excluir a senha do aplicativo \"{name}\"?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "Tem certeza que deseja descartar este rascunho?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "Tem certeza?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "Tem certeza? Esta ação não poderÔ ser desfeita."
@@ -353,15 +363,15 @@ msgstr "Nudez artĆstica ou nĆ£o erótica."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "Voltar"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "Voltar"
@@ -409,7 +419,7 @@ msgstr "Bloquear esta Lista"
msgid "Blocked"
msgstr "Bloqueado"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "Contas bloqueadas"
@@ -468,7 +478,7 @@ msgstr "Bluesky Ć© pĆŗblico."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "O Bluesky usa convites para criar uma comunidade mais saudÔvel. Se você não conhece ninguém que tenha um convite, inscreva-se na lista de espera e em breve enviaremos um para você."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "O Bluesky não mostrarÔ seu perfil e publicações para usuÔrios desconectados. Outros aplicativos podem não honrar esta solicitação. Isso não torna a sua conta privada."
@@ -520,8 +530,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Só pode conter letras, números, espaços, traços e sublinhados. Deve ter pelo menos 4 caracteres, mas não mais de 32 caracteres."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -535,7 +545,7 @@ msgstr "Só pode conter letras, números, espaços, traços e sublinhados. Deve
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "Cancelar"
@@ -686,7 +696,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "Limpar todos os dados de armazenamento (reinicie em seguida)"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "Limpar busca"
@@ -694,6 +704,11 @@ msgstr "Limpar busca"
msgid "click here"
msgstr "clique aqui"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr "Clima e tempo"
@@ -724,11 +739,15 @@ msgstr "Fechar imagem"
msgid "Close image viewer"
msgstr "Fechar visualizador de imagens"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "Fechar o painel de navegação"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "Fecha barra de navegação inferior"
@@ -736,7 +755,7 @@ msgstr "Fecha barra de navegação inferior"
msgid "Closes password update alert"
msgstr "Fecha alerta de troca de senha"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "Fecha o editor de post e descarta o rascunho"
@@ -769,7 +788,7 @@ msgstr "Completar e comeƧar a usar sua conta"
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "Escreva posts de atƩ {MAX_GRAPHEME_LENGTH} caracteres"
@@ -833,7 +852,7 @@ msgstr "Conectando..."
msgid "Contact support"
msgstr "Contatar suporte"
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Filtragem do conteĆŗdo"
@@ -899,7 +918,7 @@ msgstr "Versão do aplicativo copiada"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "Copiado"
@@ -915,7 +934,7 @@ msgstr "Copiar"
msgid "Copy link to list"
msgstr "Copiar link da lista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "Copiar link do post"
@@ -923,7 +942,7 @@ msgstr "Copiar link do post"
msgid "Copy link to profile"
msgstr "Copiar link do perfil"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "Copiar texto do post"
@@ -979,7 +998,7 @@ msgstr "Criado por <0/>"
msgid "Created by you"
msgstr "Criado por vocĆŖ"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "Cria uma prƩvia com miniatura. A prƩvia faz um link para {url}"
@@ -1056,11 +1075,11 @@ msgstr "Excluir minha conta"
msgid "Delete My Accountā¦"
msgstr "Excluir minha contaā¦"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "Excluir post"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "Excluir este post?"
@@ -1083,7 +1102,7 @@ msgstr "Descrição"
#~ msgid "Developer Tools"
#~ msgstr "Ferramentas de Desenvolvedor"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "VocĆŖ gostaria de dizer alguma coisa?"
@@ -1091,15 +1110,15 @@ msgstr "VocĆŖ gostaria de dizer alguma coisa?"
msgid "Dim"
msgstr "Menos escuro"
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "Descartar"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "Descartar rascunho"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "Desencorajar aplicativos a mostrar minha conta para usuƔrios deslogados"
@@ -1178,7 +1197,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr "Solte para adicionar imagens"
@@ -1250,6 +1269,7 @@ msgstr "Editar perfil"
msgid "Edit Profile"
msgstr "Editar Perfil"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Editar Feeds Salvos"
@@ -1332,6 +1352,11 @@ msgstr "Fim do feed"
msgid "Enter a name for this App Password"
msgstr "Insira um nome para esta Senha de Aplicativo"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "Insira o código de confirmação"
@@ -1381,7 +1406,7 @@ msgstr "Digite seu nome de usuƔrio e senha"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "Erro:"
@@ -1452,7 +1477,7 @@ msgstr "NĆ£o foi possĆvel criar senha de aplicativo."
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "NĆ£o foi possĆvel criar a lista. Por favor tente novamente."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "NĆ£o foi possĆvel excluir o post, por favor tente novamente."
@@ -1474,8 +1499,8 @@ msgid "Feed offline"
msgstr "Feed offline"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "PreferĆŖncias de Feeds"
+#~ msgid "Feed Preferences"
+#~ msgstr "PreferĆŖncias de Feeds"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1523,11 +1548,11 @@ msgstr "Finalizando"
msgid "Find accounts to follow"
msgstr "Encontre contas para seguir"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "Encontrar usuƔrios no Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "Encontre usuÔrios com a ferramenta de busca à direita"
@@ -1624,6 +1649,7 @@ msgid "Following {0}"
msgstr "Seguindo {0}"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1663,7 +1689,7 @@ msgstr "Esqueci a senha"
msgid "Forgot Password"
msgstr "Esqueci a Senha"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "Por <0/>"
@@ -1696,7 +1722,7 @@ msgstr "Voltar"
msgid "Go back to previous step"
msgstr "Voltar para o passo anterior"
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr "Ir para @{queryMaybleHandle}"
@@ -1713,6 +1739,10 @@ msgstr "Próximo"
msgid "Handle"
msgstr "UsuƔrio"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr "Precisa de ajuda?"
@@ -1751,7 +1781,7 @@ msgctxt "action"
msgid "Hide"
msgstr "Esconder"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "Ocultar post"
@@ -1760,7 +1790,7 @@ msgstr "Ocultar post"
msgid "Hide the content"
msgstr "Esconder o conteĆŗdo"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "Ocultar este post?"
@@ -1909,7 +1939,7 @@ msgstr "Insira sua senha"
msgid "Input your user handle"
msgstr "Insira o usuƔrio"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "Post invƔlido"
@@ -2011,7 +2041,7 @@ msgstr "Saiba Mais"
msgid "Learn more about this warning"
msgstr "Saiba mais sobre este aviso"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "Saiba mais sobre o que Ć© pĆŗblico no Bluesky."
@@ -2087,7 +2117,7 @@ msgstr "curtiu seu post"
msgid "Likes"
msgstr "Curtidas"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "Curtidas neste post"
@@ -2144,7 +2174,7 @@ msgstr "Carregar mais posts"
msgid "Load new notifications"
msgstr "Carregar novas notificaƧƵes"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2170,7 +2200,7 @@ msgstr "Registros"
msgid "Log out"
msgstr "Sair"
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "Visibilidade do seu perfil"
@@ -2182,6 +2212,10 @@ msgstr "Fazer login em uma conta que não estÔ listada"
msgid "Make sure this is where you intend to go!"
msgstr "Certifique-se de onde estĆ” indo!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2203,7 +2237,7 @@ msgid "Mentioned users"
msgstr "UsuƔrios mencionados"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "Menu"
@@ -2212,7 +2246,7 @@ msgid "Message from server: {0}"
msgstr "Mensagem do servidor: {0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2243,7 +2277,7 @@ msgstr "Lista de moderação criada"
msgid "Moderation list updated"
msgstr "Lista de moderação criada"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Listas de moderação"
@@ -2270,7 +2304,7 @@ msgstr "Mais feeds"
msgid "More options"
msgstr "Mais opƧƵes"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "Mais opƧƵes do post"
@@ -2282,6 +2316,14 @@ msgstr "Respostas mais curtidas primeiro"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "Silenciar Conta"
@@ -2290,6 +2332,18 @@ msgstr "Silenciar Conta"
msgid "Mute accounts"
msgstr "Silenciar contas"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "Lista de moderação"
@@ -2302,15 +2356,27 @@ msgstr "Silenciar estas contas?"
msgid "Mute this List"
msgstr "Silenciar esta lista"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "Silenciar thread"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "Silenciada"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "Contas silenciadas"
@@ -2323,6 +2389,10 @@ msgstr "Contas Silenciadas"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "Contas silenciadas não aparecem no seu feed ou nas suas notificações. Suas contas silenciadas são completamente privadas."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "Silenciar é privado. Contas silenciadas podem interagir com você, mas você não verÔ postagens ou receber notificações delas."
@@ -2386,6 +2456,10 @@ msgstr "Nunca perca o acesso aos seus seguidores e dados."
msgid "Never lose access to your followers or data."
msgstr "Nunca perca o acesso aos seus seguidores ou dados."
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2407,7 +2481,7 @@ msgstr "Nova senha"
msgid "New Password"
msgstr "Nova Senha"
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "Novo post"
@@ -2492,8 +2566,8 @@ msgid "No results found for \"{query}\""
msgstr "Nenhum resultado encontrado para \"{query}\""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "Nenhum resultado encontrado para {query}"
@@ -2519,7 +2593,7 @@ msgstr "NĆ£o encontrado"
msgid "Not right now"
msgstr "Agora não"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "Nota: o Bluesky é uma rede aberta e pública. Esta configuração limita somente a visibilidade do seu conteúdo no site e aplicativo do Bluesky, e outros aplicativos podem não respeitar esta configuração. Seu conteúdo ainda poderÔ ser exibido para usuÔrios deslogados por outros aplicativos e sites."
@@ -2557,7 +2631,7 @@ msgstr "Respostas mais antigas primeiro"
msgid "Onboarding reset"
msgstr "Resetar tutoriais"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "Uma ou mais imagens estão sem texto alternativo."
@@ -2574,8 +2648,12 @@ msgstr "Opa!"
msgid "Open"
msgstr "Abrir"
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "Abrir seletor de emojis"
@@ -2583,6 +2661,10 @@ msgstr "Abrir seletor de emojis"
msgid "Open links with in-app browser"
msgstr "Abrir links no navegador interno"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "Abrir navegação"
@@ -2659,6 +2741,7 @@ msgstr "Abre configurações de moderação"
msgid "Opens password reset form"
msgstr "Abre o formulÔrio de redefinição de senha"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "Abre a tela para editar feeds salvos"
@@ -2839,7 +2922,7 @@ msgstr "Por favor, diga-nos por que vocĆŖ acha que este aviso de conteĆŗdo foi a
msgid "Please Verify Your Email"
msgstr "Por favor, verifique seu e-mail"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "Aguarde atƩ que a prƩvia de link termine de carregar"
@@ -2851,8 +2934,8 @@ msgstr "PolĆtica"
msgid "Porn"
msgstr "Pornografia"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "Postar"
@@ -2862,7 +2945,7 @@ msgctxt "description"
msgid "Post"
msgstr "Post"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "Post por {0}"
@@ -2872,11 +2955,11 @@ msgstr "Post por {0}"
msgid "Post by @{0}"
msgstr "Post por @{0}"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "Post excluĆdo"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "Post oculto"
@@ -2888,14 +2971,22 @@ msgstr "Idioma do post"
msgid "Post Languages"
msgstr "Idiomas do Post"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "Post não encontrado"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "Posts"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "Posts ocultados"
@@ -2960,11 +3051,11 @@ msgstr "Listas públicas e compartilhÔveis para silenciar ou bloquear usuÔrios
msgid "Public, shareable lists which can drive feeds."
msgstr "Listas públicas e compartilhÔveis que geram feeds."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "Publicar post"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "Publicar resposta"
@@ -2998,6 +3089,7 @@ msgstr "Feeds Recomendados"
msgid "Recommended Users"
msgstr "UsuƔrios Recomendados"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3035,6 +3127,10 @@ msgstr "Remover imagem"
msgid "Remove image preview"
msgstr "Remover visualização da imagem"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "Desfazer repost"
@@ -3069,7 +3165,7 @@ msgstr "Respostas"
msgid "Replies to this thread are disabled"
msgstr "Respostas para esta thread estão desativadas"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "Responder"
@@ -3079,7 +3175,7 @@ msgid "Reply Filters"
msgstr "Filtros de Resposta"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "Responder <0/>"
@@ -3101,7 +3197,7 @@ msgid "Report List"
msgstr "Denunciar Lista"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "Denunciar post"
@@ -3126,11 +3222,11 @@ msgstr "Repostar ou citar um post"
msgid "Reposted By"
msgstr "Repostado Por"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr "Repostado por {0}"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "Repostado por <0/>"
@@ -3138,7 +3234,7 @@ msgstr "Repostado por <0/>"
msgid "reposted your post"
msgstr "repostou seu post"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "Reposts"
@@ -3289,9 +3385,9 @@ msgstr "Ir para o topo"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3301,11 +3397,19 @@ msgstr "Ir para o topo"
msgid "Search"
msgstr "Buscar"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr "Pesquisar por \"{query}\""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3316,6 +3420,22 @@ msgstr "Buscar usuƔrios"
msgid "Security Step Required"
msgstr "Passo de SeguranƧa NecessƔrio"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "Veja o guia"
@@ -3525,7 +3645,7 @@ msgid "Share"
msgstr "Compartilhar"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "Compartilhar"
@@ -3558,9 +3678,9 @@ msgstr "Mostrar anexos de {0}"
msgid "Show follows similar to {0}"
msgstr "Mostrar usuƔrios parecidos com {0}"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "Mostrar Mais"
@@ -3728,7 +3848,7 @@ msgstr "Desenvolvimento de software"
msgid "Something went wrong. Check your email and try again."
msgstr "Algo deu errado. Verifique seu e-mail e tente novamente."
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "Opa! Sua sessão expirou. Por favor, entre novamente."
@@ -3786,7 +3906,7 @@ msgstr "Increver-se no feed {0}"
msgid "Subscribe to this list"
msgstr "Inscreva-se nesta lista"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "SugestƵes de Seguidores"
@@ -3830,6 +3950,14 @@ msgstr "Sistema"
msgid "System log"
msgstr "Log do sistema"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "Alto"
@@ -3853,6 +3981,10 @@ msgstr "Termos"
msgid "Terms of Service"
msgstr "Termos de ServiƧo"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3878,7 +4010,7 @@ msgstr "A PolĆtica de Direitos Autorais foi movida para <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr "Os seguintes passos vão ajudar a customizar sua experiência no Bluesky."
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "O post pode ter sido excluĆdo."
@@ -4044,7 +4176,7 @@ msgstr "Esta lista estĆ” vazia!"
msgid "This name is already in use"
msgstr "VocĆŖ jĆ” tem uma senha com esse nome"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Este post foi excluĆdo."
@@ -4068,7 +4200,11 @@ msgstr "Este usuĆ”rio estĆ” incluĆdo na lista <0/>, que vocĆŖ silenciou."
msgid "This warning is only available for posts with media attached."
msgstr "Este aviso só estĆ” disponĆvel para publicaƧƵes com mĆdia anexada."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Isso ocultarĆ” este post de seus feeds."
@@ -4085,6 +4221,10 @@ msgstr "Visualização de Threads"
msgid "Threads Preferences"
msgstr "PreferĆŖncias das Threads"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Alternar menu suspenso"
@@ -4093,9 +4233,9 @@ msgstr "Alternar menu suspenso"
msgid "Transformations"
msgstr "TransformaƧƵes"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "Traduzir"
@@ -4160,15 +4300,24 @@ msgstr "Infelizmente, você não atende aos requisitos para criar uma conta."
msgid "Unlike"
msgstr "Descurtir"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "Dessilenciar"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "Dessilenciar conta"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "Dessilenciar thread"
@@ -4369,6 +4518,10 @@ msgstr "Não temos mais posts de quem você segue. Aqui estão os mais novos de
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr "Recomendamos o \"Para vocĆŖ\", do Skygaze:"
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr "Recomendamos nosso feed \"Discover\":"
@@ -4397,7 +4550,11 @@ msgstr "Estamos muito felizes em recebĆŖ-lo!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "Tivemos um problema ao exibir esta lista. Se continuar acontecendo, contate o criador da lista: @{handleOrDid}."
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "Lamentamos, mas sua busca nĆ£o pĆ“de ser concluĆda. Por favor, tente novamente em alguns minutos."
@@ -4418,7 +4575,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "Qual Ć© o problema com este {collectionName}?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "E aĆ?"
@@ -4439,11 +4596,11 @@ msgstr "Quem pode responder"
msgid "Wide"
msgstr "Largo"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "Escrever post"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "Escreva sua resposta"
@@ -4508,7 +4665,7 @@ msgstr "Você não tem feeds salvos!"
msgid "You don't have any saved feeds."
msgstr "Você não tem feeds salvos."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "VocĆŖ bloqueou esta conta ou foi bloqueado por ela."
@@ -4548,6 +4705,10 @@ msgstr "Você ainda não criou nenhuma senha de aplicativo. Você pode criar uma
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "Você ainda não silenciou nenhuma conta. Para silenciar uma conta, acesse um perfil e selecione \"Silenciar conta\" no menu."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "VocĆŖ precisa ser maior de idade para habilitar conteĆŗdo adulto."
@@ -4556,11 +4717,11 @@ msgstr "VocĆŖ precisa ser maior de idade para habilitar conteĆŗdo adulto."
msgid "You must be 18 years or older to enable adult content"
msgstr "VocĆŖ precisa ser maior de idade para habilitar conteĆŗdo adulto."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "Você não vai mais receber notificações desta thread"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "Você vai receber notificações desta thread"
@@ -4646,11 +4807,15 @@ msgstr "Seu usuƔrio completo serƔ <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "Seus códigos de convite estão ocultos quando conectado com uma Senha do Aplicativo"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr "Sua senha foi alterada com sucesso!"
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "Seu post foi publicado"
@@ -4665,7 +4830,7 @@ msgstr "Suas postagens, curtidas e bloqueios são públicos. Silenciamentos são
msgid "Your profile"
msgstr "Seu perfil"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "Sua resposta foi publicada"
diff --git a/src/locale/locales/uk/messages.po b/src/locale/locales/uk/messages.po
index 169b1feb78..8f978261ff 100644
--- a/src/locale/locales/uk/messages.po
+++ b/src/locale/locales/uk/messages.po
@@ -118,7 +118,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "ŠŠ¾ŃŃŃŠæŠ½Š° нова веŃŃŃŃ. ŠŃŠ“Ń Š»Š°ŃŠŗŠ°, оновŃŃŃ Š·Š°ŃŃŠ¾ŃŃŠ½Š¾Šŗ, ŃŠ¾Š± ŠæŃŠ¾Š“Š¾Š²Š¶ŠøŃŠø ним ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŠøŃŃ."
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr ""
@@ -169,6 +169,7 @@ msgstr ""
msgid "Account unmuted"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -210,14 +211,22 @@ msgstr "ŠŠ¾Š“Š°Š¹ŃŠµ ŠæŠ¾Š“ŃŠ¾Š±ŠøŃŃ"
msgid "Add details to report"
msgstr "ŠŠ¾Š“Š°Š¹ŃŠµ ŠæŠ¾Š“ŃŠ¾Š±ŠøŃŃ Š“Š¾ ŃŠŗŠ°Ńги"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "ŠŠ¾Š“Š°ŃŠø ŠæŠ¾ŠæŠµŃŠµŠ“Š½ŃŠ¹ ŠæŠµŃŠµŠ³Š»ŃŠ“"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "ŠŠ¾Š“Š°ŃŠø ŠæŠ¾ŠæŠµŃŠµŠ“Š½ŃŠ¹ ŠæŠµŃŠµŠ³Š»ŃŠ“:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "ŠŠ¾Š“Š°Š¹ŃŠµ наŃŃŃŠæŠ½ŠøŠ¹ DNS-Š·Š°ŠæŠøŃ Š“Š¾ Š²Š°ŃŠ¾Š³Š¾ ГоменŃ:"
@@ -341,7 +350,7 @@ msgstr ""
msgid "App Passwords"
msgstr "ŠŠ°ŃŠ¾Š»Ń Š“Š»Ń Š·Š°ŃŃŠ¾ŃŃŠ½ŠŗŃв"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "ŠŃŠŗŠ°ŃŠ¶ŠøŃŠø ŠæŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń ŠæŃŠ¾ вмŃŃŃ"
@@ -373,15 +382,16 @@ msgstr "ŠŃŠ¾ŃŠ¼Š»ŠµŠ½Š½Ń"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "ŠŠø Š“ŃŠ¹Ńно Ń
Š¾ŃŠµŃе Š²ŠøŠ“Š°Š»ŠøŃŠø ŠæŠ°ŃŠ¾Š»Ń Š“Š»Ń Š·Š°ŃŃŠ¾ŃŃŠ½ŠŗŃ \"{name}\"?"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "ŠŠø Š“ŃŠ¹Ńно бажаŃŃŠµ Š²ŠøŠ“Š°Š»ŠøŃŠø ŃŃ ŃŠµŃŠ½ŠµŃŠŗŃ?"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "ŠŠø впевненŃ?"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "ŠŠø впевненŃ? Це не можна Š±ŃŠ“е ŃŠŗŠ°ŃŃŠ²Š°ŃŠø."
@@ -407,15 +417,15 @@ msgstr "Š„ŃŠ“Š¾Š¶Š½Ń Š°Š±Š¾ Š½ŠµŠµŃŠ¾ŃŠøŃŠ½Š° оголенŃŃŃŃ."
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "ŠŠ°Š·Š°Š“"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr ""
@@ -463,7 +473,7 @@ msgstr ""
msgid "Blocked"
msgstr ""
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "ŠŠ°Š±Š»Š¾ŠŗŠ¾Š²Š°Š½Ń Š¾Š±Š»ŃŠŗŠ¾Š²Ń Š·Š°ŠæŠøŃŠø"
@@ -522,7 +532,7 @@ msgstr "Bluesky ŠæŃŠ±Š»ŃŃŠ½ŠøŠ¹."
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŃ ŃŠøŃŃŠµŠ¼Ń Š·Š°ŠæŃŠ¾ŃŠµŠ½Ń Š“Š»Ń ŃŃŠ²Š¾ŃŠµŠ½Š½Ń Š·Š“Š¾ŃŠ¾Š²ŃŃŠ¾Ń ŃŠæŃŠ»ŃŠ½Š¾ŃŠø. ŠÆŠŗŃŠ¾ ŠŠø не знаŃŃŠµ когоŃŃ Ń
ŃŠ¾ Š¼Š°Ń Š·Š°ŠæŃŠ¾ŃеннŃ, ви Š¼Š¾Š¶ŠµŃе Š·Š°ŠæŠøŃŠ°ŃŠøŃŃ Š“Š¾ ŃŠµŃги оŃŃŠŗŃŠ²Š°Š½Š½Ń Ń Š¼Šø ŃŠŗŠ¾Ńо наГŃŃŠ»ŠµŠ¼Š¾ вам коГ Š·Š°ŠæŃŠ¾ŃеннŃ."
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky не Š±ŃŠ“е ŠæŠ¾ŠŗŠ°Š·ŃŠ²Š°ŃŠø Š²Š°Ń ŠæŃŠ¾ŃŃŠ»Ń Ń ŠæŠ¾Š²ŃŠ“Š¾Š¼Š»ŠµŠ½Š½Ń Š²ŃŠ“Š²ŃŠ“ŃŠ²Š°Ńам без Š¾Š±Š»Ńкового запиŃŃ. ŠŠ½ŃŃ Š·Š°ŃŃŠ¾ŃŃŠ½ŠŗŠø можŃŃŃ Š½Šµ ŃŠ»ŃŠ“ŃŠ²Š°ŃŠø ŃŃŠ¾Š¼Ń запиŃŃ. Це не ŃŠ¾Š±ŠøŃŃ Š²Š°Ń Š¾Š±Š»ŃŠŗŠ¾Š²ŠøŠ¹ Š·Š°ŠæŠøŃ ŠæŃŠøŠ²Š°Ńним."
@@ -574,8 +584,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "ŠŠ¾Š¶Šµ мŃŃŃŠøŃŠø Š»ŠøŃŠµ Š»ŃŃŠµŃŠø, ŃŠøŃŃŠø, ŠæŃŠ¾Š±Ńли, ГеŃŃŃŠø ŃŠ° знаки ŠæŃŠ“ŠŗŃŠµŃленнŃ, Ń Š¼Š°ŃŠø Š“Š¾Š²Š¶ŠøŠ½Ń Š²ŃŠ“ 4 Го 32 ŃŠøŠ¼Š²Š¾Š»Ńв."
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -589,7 +599,7 @@ msgstr "ŠŠ¾Š¶Šµ мŃŃŃŠøŃŠø Š»ŠøŃŠµ Š»ŃŃŠµŃŠø, ŃŠøŃŃŠø, ŠæŃŠ¾Š±ŃŠ»
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "ДкаŃŃŠ²Š°ŃŠø"
@@ -752,7 +762,7 @@ msgid "Clear all storage data (restart after this)"
msgstr ""
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "ŠŃŠøŃŃŠøŃŠø поŃŃŠŗŠ¾Š²ŠøŠ¹ запиŃ"
@@ -760,6 +770,11 @@ msgstr "ŠŃŠøŃŃŠøŃŠø поŃŃŠŗŠ¾Š²ŠøŠ¹ запиŃ"
msgid "click here"
msgstr ""
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr ""
@@ -790,11 +805,15 @@ msgstr "ŠŠ°ŠŗŃŠøŃŠø Š·Š¾Š±ŃŠ°Š¶ŠµŠ½Š½Ń"
msgid "Close image viewer"
msgstr "ŠŠ°ŠŗŃŠøŃŠø ŠæŠµŃŠµŠ³Š»ŃŠ“ Š·Š¾Š±ŃŠ°Š¶ŠµŠ½Š½Ń"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "ŠŠ°ŠŗŃŠøŃŠø ŠæŠ°Š½ŠµŠ»Ń Š½Š°Š²ŃŠ³Š°ŃŃŃ"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr ""
@@ -802,7 +821,7 @@ msgstr ""
msgid "Closes password update alert"
msgstr ""
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr ""
@@ -835,7 +854,7 @@ msgstr ""
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr ""
@@ -899,7 +918,7 @@ msgstr "ŠāŃŠ“наннŃ..."
msgid "Contact support"
msgstr ""
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "Š¤ŃŠ»ŃŃŃŃŠ²Š°Š½Š½Ń вмŃŃŃŃ"
@@ -965,7 +984,7 @@ msgstr ""
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr ""
@@ -981,7 +1000,7 @@ msgstr "ДкопŃŃŠ²Š°ŃŠø"
msgid "Copy link to list"
msgstr "ДкопŃŃŠ²Š°ŃŠø ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "ДкопŃŃŠ²Š°ŃŠø ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń"
@@ -989,7 +1008,7 @@ msgstr "ДкопŃŃŠ²Š°ŃŠø ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń"
msgid "Copy link to profile"
msgstr "ДкопŃŃŠ²Š°ŃŠø ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "ДкопŃŃŠ²Š°ŃŠø ŃŠµŠŗŃŃ"
@@ -1045,7 +1064,7 @@ msgstr ""
msgid "Created by you"
msgstr ""
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr ""
@@ -1126,11 +1145,11 @@ msgstr "ŠŠøŠ“Š°Š»ŠøŃŠø Š¼ŃŠ¹ Š¾Š±Š»ŃŠŗŠ¾Š²ŠøŠ¹ запиŃ"
msgid "Delete My Accountā¦"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "ŠŠøŠ“Š°Š»ŠøŃŠø поŃŃ"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "ŠŠøŠ“Š°Š»ŠøŃŠø ŃŠµŠ¹ поŃŃ?"
@@ -1157,7 +1176,7 @@ msgstr "ŠŠæŠøŃ"
#~ msgid "Developer Tools"
#~ msgstr "ŠŠ½ŃŃŃŃŠ¼ŠµŠ½ŃŠø ŃŠ¾Š·Ńобника"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "ŠŠ¾ŃŠ¾Š¶Š½ŃŠ¹ поŃŃ. ŠŠø Ń
оŃŃŠ»Šø ŃŠ¾ŃŃ Š½Š°ŠæŠøŃŠ°ŃŠø?"
@@ -1165,15 +1184,15 @@ msgstr "ŠŠ¾ŃŠ¾Š¶Š½ŃŠ¹ поŃŃ. ŠŠø Ń
оŃŃŠ»Šø ŃŠ¾ŃŃ Š½Š°ŠæŠøŃŠ°ŃŠø?"
msgid "Dim"
msgstr ""
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "ŠŠøŠ“Š°Š»ŠøŃŠø"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "ŠŃГкинŃŃŠø ŃŠµŃŠ½ŠµŃŠŗŃ"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "ŠŠ¾ŠæŃŠ¾ŃŠøŃŠø заŃŃŠ¾ŃŃŠ½ŠŗŠø не ŠæŠ¾ŠŗŠ°Š·ŃŠ²Š°ŃŠø Š¼ŃŠ¹ Š¾Š±Š»ŃŠŗŠ¾Š²ŠøŠ¹ Š·Š°ŠæŠøŃ Š±ŠµŠ· вŃ
оГŃ"
@@ -1252,7 +1271,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr ""
@@ -1324,6 +1343,7 @@ msgstr "Š ŠµŠ“Š°Š³ŃŠ²Š°ŃŠø ŠæŃŠ¾ŃŃŠ»Ń"
msgid "Edit Profile"
msgstr "Š ŠµŠ“Š°Š³ŃŠ²Š°ŃŠø ŠæŃŠ¾ŃŃŠ»Ń"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "Š ŠµŠ“Š°Š³ŃŠ²Š°ŃŠø Š·Š±ŠµŃŠµŠ¶ŠµŠ½Ń ŃŃŃŃŃŠŗŠø"
@@ -1406,6 +1426,11 @@ msgstr "ŠŃнеŃŃ ŃŃŃŃŃŠŗŠø"
msgid "Enter a name for this App Password"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr ""
@@ -1459,7 +1484,7 @@ msgstr "ŠŠ²ŠµŠ“ŃŃŃ ŠæŃŠµŠ²Š“Š¾Š½ŃŠ¼ ŃŠ° ŠæŠ°ŃŠ¾Š»Ń"
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°:"
@@ -1530,7 +1555,7 @@ msgstr ""
msgid "Failed to create the list. Check your internet connection and try again."
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr ""
@@ -1552,8 +1577,8 @@ msgid "Feed offline"
msgstr "Š”ŃŃŃŃŠŗŠ° не ŠæŃаŃŃŃ"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "ŠŠ°Š»Š°ŃŃŃŠ²Š°Š½Š½Ń ŃŃŃŃŃŠŗŠø"
+#~ msgid "Feed Preferences"
+#~ msgstr "ŠŠ°Š»Š°ŃŃŃŠ²Š°Š½Š½Ń ŃŃŃŃŃŠŗŠø"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1601,11 +1626,11 @@ msgstr ""
msgid "Find accounts to follow"
msgstr ""
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "ŠŠ½Š°Š¹ŃŠø ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃŠ² Ń Bluesky"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "ŠŠ½Š°Š¹ŃŠø ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃŠ² за Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń ŠæŠ¾Š»Ń ŠæŠ¾ŃŃŠŗŃ ŃŠæŃава вгоŃŃ"
@@ -1714,6 +1739,7 @@ msgid "Following {0}"
msgstr ""
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1753,7 +1779,7 @@ msgstr "ŠŠ°Š±Ńли ŠæŠ°ŃŠ¾Š»Ń"
msgid "Forgot Password"
msgstr "ŠŠ°Š±Ńли ŠæŠ°ŃŠ¾Š»Ń"
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr ""
@@ -1786,7 +1812,7 @@ msgstr "ŠŠ°Š·Š°Š“"
msgid "Go back to previous step"
msgstr ""
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr ""
@@ -1803,6 +1829,10 @@ msgstr "ŠŠ°Š»Ń"
msgid "Handle"
msgstr "ŠŃŠµŠ²Š“Š¾Š½ŃŠ¼"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr ""
@@ -1845,7 +1875,7 @@ msgctxt "action"
msgid "Hide"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "ŠŃŠøŃ
Š¾Š²Š°ŃŠø поŃŃ"
@@ -1854,7 +1884,7 @@ msgstr "ŠŃŠøŃ
Š¾Š²Š°ŃŠø поŃŃ"
msgid "Hide the content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "ŠŃŠøŃ
Š¾Š²Š°ŃŠø ŃŠµŠ¹ поŃŃ?"
@@ -2029,7 +2059,7 @@ msgstr ""
msgid "Input your user handle"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr ""
@@ -2131,7 +2161,7 @@ msgstr "ŠŃŠ·Š½Š°ŃŠøŃŃ Š±ŃŠ»ŃŃŠµ"
msgid "Learn more about this warning"
msgstr "ŠŃŠ·Š½Š°ŃŠøŃŃ Š±ŃŠ»ŃŃŠµ ŠæŃŠ¾ ŃŠµ ŠæŠ¾ŠæŠµŃŠµŠ“женнŃ"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "ŠŃŠ·Š½Š°ŃŠøŃŃ Š±ŃŠ»ŃŃŠµ ŠæŃŠ¾ ŃŠµ, ŃŠ¾ Ń ŠæŃŠ±Š»ŃŃŠ½ŠøŠ¼ в Bluesky."
@@ -2215,7 +2245,7 @@ msgstr ""
msgid "Likes"
msgstr "ŠŠæŠ¾Š“Š¾Š±Š°Š½Š½Ń"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr ""
@@ -2280,7 +2310,7 @@ msgstr "ŠŠ°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø Š±ŃŠ»ŃŃŠµ поŃŃŃŠ²"
msgid "Load new notifications"
msgstr "ŠŠ°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø Š½Š¾Š²Ń ŃŠæŠ¾Š²ŃŃŠµŠ½Š½Ń"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2310,7 +2340,7 @@ msgstr ""
#~ msgid "Logged-out users"
#~ msgstr ""
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "ŠŠøŠ“имŃŃŃŃ Š“Š»Ń ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃŠ² без Š¾Š±Š»Ńкового запиŃŃ"
@@ -2326,6 +2356,10 @@ msgstr "Š£Š²ŃŠ¹ŃŠø Го Š¾Š±Š»Ńкового запиŃŃ, ŃŠŗŠ¾Š³Š¾ нема
msgid "Make sure this is where you intend to go!"
msgstr "ŠŠµŃŠµŠŗŠ¾Š½Š°Š¹ŃŠµŃŃ, ŃŠ¾ ŃŠµ Š“ŃŠ¹Ńно ŃŠ¾Š¹ ŃŠ°Š¹Ń, ŃŠ¾ ви Š·Š±ŠøŃаŃŃŠµŃŃ Š²ŃŠ“Š²ŃŠ“Š°ŃŠø!"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2347,7 +2381,7 @@ msgid "Mentioned users"
msgstr "ŠŠ³Š°Š“Š°Š½Ń ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃ"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "ŠŠµŠ½Ń"
@@ -2360,7 +2394,7 @@ msgid "Message from server: {0}"
msgstr ""
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2391,7 +2425,7 @@ msgstr ""
msgid "Moderation list updated"
msgstr ""
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "Š”ŠæŠøŃŠŗŠø Š“Š»Ń Š¼Š¾Š“ŠµŃŠ°ŃŃŃ"
@@ -2418,7 +2452,7 @@ msgstr "ŠŃŠ»ŃŃŠµ ŃŃŃŃŃŠ¾Šŗ"
msgid "More options"
msgstr "ŠŠ¾Š“Š°ŃŠŗŠ¾Š²Ń опŃŃŃ"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr ""
@@ -2430,6 +2464,14 @@ msgstr "ŠŠ° ŠŗŃŠ»ŃŠŗŃŃŃŃ Š²ŠæŠ¾Š“Š¾Š±Š°Š½Ń"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø Š¾Š±Š»ŃŠŗŠ¾Š²ŠøŠ¹ запиŃ"
@@ -2438,6 +2480,18 @@ msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø Š¾Š±Š»ŃŠŗŠ¾Š²ŠøŠ¹ запиŃ"
msgid "Mute accounts"
msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø Š¾Š±Š»ŃŠŗŠ¾Š²Ń Š·Š°ŠæŠøŃŠø"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø ŃŠæŠøŃŠ¾Šŗ"
@@ -2450,15 +2504,27 @@ msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø ŃŃ Š¾Š±Š»ŃŠŗŠ¾Š²Ń Š·Š°ŠæŠøŃŠø?"
msgid "Mute this List"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø поŃŃ"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr ""
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "ŠŠ³Š½Š¾ŃŠ¾Š²Š°Š½Ń Š¾Š±Š»ŃŠŗŠ¾Š²Ń Š·Š°ŠæŠøŃŠø"
@@ -2471,6 +2537,10 @@ msgstr "ŠŠ³Š½Š¾ŃŠ¾Š²Š°Š½Ń Š¾Š±Š»ŃŠŗŠ¾Š²Ń Š·Š°ŠæŠøŃŠø"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "ŠŠ³Š½Š¾ŃŠ¾Š²Š°Š½Ń Š¾Š±Š»ŃŠŗŠ¾Š²Ń Š·Š°ŠæŠøŃŠø Š°Š²ŃŠ¾Š¼Š°ŃŠøŃŠ½Š¾ вилŃŃŠ°ŃŃŃŃŃ ŃŠ· Š²Š°ŃŠ¾Ń ŃŃŃŃŃŠŗŠø ŃŠ° ŃŠæŠ¾Š²ŃŃŠµŠ½Ń. ŠŠ³Š½Š¾ŃŃŠ²Š°Š½Š½Ń Ń ŠæŠ¾Š²Š½ŃŃŃŃ ŠæŃŠøŠ²Š°Ńним."
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "ŠŠ³Š½Š¾ŃŃŠ²Š°Š½Š½Ń Ń ŠæŃŠøŠ²Š°Ńним. ŠŠ³Š½Š¾ŃŠ¾Š²Š°Š½Ń ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃ Š¼Š¾Š¶ŃŃŃ Š²Š·Š°ŃŠ¼Š¾Š“ŃŃŃŠø Š· вами, але ви не Š±Š°ŃŠøŃŠøŠ¼ŠµŃе ŃŃ
поŃŃŠø Ń Š½Šµ оŃŃŠøŠ¼ŃŠ²Š°ŃŠøŠ¼ŠµŃе Š²ŃŠ“ ниŃ
ŃŠæŠ¾Š²ŃŃŠµŠ½Ń."
@@ -2538,6 +2608,10 @@ msgstr "ŠŃколи не вŃŃŠ°ŃŠ°Š¹ŃŠµ ГоŃŃŃŠæ Š“о Š²Š°ŃŠøŃ
Ган
msgid "Never lose access to your followers or data."
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2559,7 +2633,7 @@ msgstr ""
msgid "New Password"
msgstr ""
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr ""
@@ -2653,8 +2727,8 @@ msgstr "ŠŃŃŠ¾Š³Š¾ не знайГено за Š·Š°ŠæŠøŃом Ā«{query}Ā»"
#~ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "ŠŃŃŠ¾Š³Š¾ не знайГено за Š·Š°ŠæŠøŃом Ā«{query}Ā»"
@@ -2688,7 +2762,7 @@ msgstr ""
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
#~ msgstr ""
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "ŠŃимŃŃŠŗŠ°: Bluesky Ń Š²ŃŠ“ŠŗŃŠøŃŠ¾Ń Ń ŠæŃŠ±Š»ŃŃŠ½Š¾Ń Š¼ŠµŃŠµŠ¶ŠµŃ. Цей ŠæŠ°ŃŠ°Š¼ŠµŃŃ Š¾Š±Š¼ŠµŠ¶ŃŃ Š²ŠøŠ“ŠøŠ¼ŃŃŃŃ Š²Š°ŃŠ¾Š³Š¾ вмŃŃŃŃ Š»ŠøŃŠµ Ń Š·Š°ŃŃŠ¾ŃŃŠ½ŠŗŠ°Ń
Ń Š½Š° ŃŠ°Š¹ŃŃ Bluesky, але ŃŠ½ŃŃ Š·Š°ŃŃŠ¾ŃŃŠ½ŠŗŠø можŃŃŃ ŃŃŠ¾Š³Š¾ не ГоŃŃŠøŠ¼ŃŠ²Š°ŃŠøŃŃ. ŠŠ°Ń вмŃŃŃ Š²ŃŠµ ŃŠµ може бŃŃŠø показаний Š²ŃŠ“Š²ŃŠ“ŃŠ²Š°Ńам без Š¾Š±Š»Ńкового запиŃŃ ŃŠ½Ńими заŃŃŠ¾ŃŃŠ½ŠŗŠ°Š¼Šø Ń Š²ŠµŠ±ŃŠ°Š¹Ńами."
@@ -2730,7 +2804,7 @@ msgstr "Š”ŠæŠ¾ŃŠ°ŃŠŗŃ Š½Š°Š¹Š“Š°Š²Š½ŃŃŃ"
msgid "Onboarding reset"
msgstr ""
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "ŠŠ»Ń оГного або ŠŗŃŠ»ŃкоŃ
Š·Š¾Š±ŃŠ°Š¶ŠµŠ½Ń Š²ŃŠ“ŃŃŃŠ½Ńй алŃŃŠµŃŠ½Š°ŃŠøŠ²Š½ŠøŠ¹ ŃŠµŠŗŃŃ."
@@ -2747,8 +2821,12 @@ msgstr ""
msgid "Open"
msgstr ""
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "ŠŠ¼Š¾Š“жŃ"
@@ -2756,6 +2834,10 @@ msgstr "ŠŠ¼Š¾Š“жŃ"
msgid "Open links with in-app browser"
msgstr ""
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "ŠŃŠ“ŠŗŃŠøŃŠø Š½Š°Š²ŃŠ³Š°ŃŃŃ"
@@ -2832,6 +2914,7 @@ msgstr "ŠŃŠ“ŠŗŃŠøŠ²Š°Ń налаŃŃŃŠ²Š°Š½Š½Ń Š¼Š¾Š“ŠµŃŠ°ŃŃŃ"
msgid "Opens password reset form"
msgstr ""
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr ""
@@ -3016,7 +3099,7 @@ msgstr "ŠŃŠ“Ń Š»Š°ŃŠŗŠ°, вкажŃŃŃ ŃŠ¾Š¼Ń ви вважаŃŃŠµ ŃŠ¾
msgid "Please Verify Your Email"
msgstr ""
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "ŠŃŠ“Ń Š»Š°ŃŠŗŠ°, Š·Š°ŃŠµŠŗŠ°Š¹Ńе Гоки завеŃŃŠøŃŃŃŃ ŃŃŠ²Š¾ŃŠµŠ½Š½Ń ŠæŠ¾ŠæŠµŃŠµŠ“Š½ŃŠ¾Š³Š¾ ŠæŠµŃŠµŠ³Š»ŃŠ“Ń Š“Š»Ń ŠæŠ¾ŃŠøŠ»Š°Š½Š½Ń"
@@ -3028,8 +3111,8 @@ msgstr ""
msgid "Porn"
msgstr ""
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr ""
@@ -3045,7 +3128,7 @@ msgstr ""
#~ msgid "Post"
#~ msgstr "ŠŠ¾ŃŃ"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr ""
@@ -3055,11 +3138,11 @@ msgstr ""
msgid "Post by @{0}"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "ŠŠ¾ŃŃ ŠæŃŠøŃ
овано"
@@ -3071,14 +3154,22 @@ msgstr "ŠŠ¾Š²Š° поŃŃŃ"
msgid "Post Languages"
msgstr "ŠŠ¾Š²Šø поŃŃŃ"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "ŠŠ¾ŃŃ Š½Šµ знайГено"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "ŠŠ¾ŃŃŠø"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr ""
@@ -3143,11 +3234,11 @@ msgstr "ŠŃблŃŃŠ½Ń, ŠæŠ¾ŃŠøŃŃŠ²Š°Š½Ń ŃŠæŠøŃŠŗŠø ŠŗŠ¾ŃŠøŃŃŃŠ²Š°Ń
msgid "Public, shareable lists which can drive feeds."
msgstr "ŠŃблŃŃŠ½Ń, ŠæŠ¾ŃŠøŃŃŠ²Š°Š½Ń ŃŠæŠøŃŠŗŠø Š“Š»Ń ŃŃŠ²Š¾ŃŠµŠ½Š½Ń ŃŃŃŃŃŠ¾Šŗ."
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr ""
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr ""
@@ -3190,6 +3281,7 @@ msgstr "Š ŠµŠŗŠ¾Š¼ŠµŠ½Š“Š¾Š²Š°Š½Ń ŃŃŃŃŃŠŗŠø"
msgid "Recommended Users"
msgstr "Š ŠµŠŗŠ¾Š¼ŠµŠ½Š“Š¾Š²Š°Š½Ń ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃ"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3227,6 +3319,10 @@ msgstr "ŠŠøŠ»ŃŃŠøŃŠø Š·Š¾Š±ŃŠ°Š¶ŠµŠ½Š½Ń"
msgid "Remove image preview"
msgstr "ŠŠøŠ»ŃŃŠøŃŠø ŠæŠ¾ŠæŠµŃŠµŠ“Š½ŃŠ¹ ŠæŠµŃŠµŠ³Š»ŃŠ“ Š·Š¾Š±ŃŠ°Š¶ŠµŠ½Š½Ń"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr ""
@@ -3261,7 +3357,7 @@ msgstr "ŠŃŠ“ŠæŠ¾Š²ŃŠ“Ń"
msgid "Replies to this thread are disabled"
msgstr "ŠŃŠ“ŠæŠ¾Š²ŃŠ“Ń Š“Š¾ ŃŃŠ¾Š³Š¾ поŃŃŃ Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr ""
@@ -3271,7 +3367,7 @@ msgid "Reply Filters"
msgstr "ŠÆŠŗŃ Š²ŃŠ“ŠæŠ¾Š²ŃŠ“Ń ŠæŠ¾ŠŗŠ°Š·ŃŠ²Š°ŃŠø"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr ""
@@ -3293,7 +3389,7 @@ msgid "Report List"
msgstr "ŠŠ¾ŃŠŗŠ°ŃŠ¶ŠøŃŠøŃŃ Š½Š° ŃŠæŠøŃŠ¾Šŗ"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "ŠŠ¾ŃŠŗŠ°ŃŠ¶ŠøŃŠøŃŃ Š½Š° поŃŃ"
@@ -3322,7 +3418,7 @@ msgstr "РепоŃŃŠøŃŠø або ŃŠøŃŃŠ²Š°ŃŠø"
msgid "Reposted By"
msgstr ""
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr ""
@@ -3330,7 +3426,7 @@ msgstr ""
#~ msgid "Reposted by {0})"
#~ msgstr ""
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr ""
@@ -3338,7 +3434,7 @@ msgstr ""
msgid "reposted your post"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr ""
@@ -3501,9 +3597,9 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3513,11 +3609,19 @@ msgstr ""
msgid "Search"
msgstr "ŠŠ¾ŃŃŠŗ"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr ""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/screens/Search/Search.tsx:390
#~ msgid "Search for posts and users."
#~ msgstr ""
@@ -3532,6 +3636,22 @@ msgstr "ŠŠ¾ŃŃŠŗ ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŃŠ²"
msgid "Security Step Required"
msgstr "ŠŠ¾ŃŃŃŠ±ŠµŠ½ коГ ŠæŃŠ“ŃŠ²ŠµŃГженнŃ"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr ""
@@ -3749,7 +3869,7 @@ msgid "Share"
msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "ŠŠ¾ŃŠøŃŠøŃŠø"
@@ -3786,9 +3906,9 @@ msgstr "ŠŠ¾ŠŗŠ°Š·Š°ŃŠø Š²Š±ŃŠ“ŃŠ²Š°Š½Š½Ń Š· {0}"
msgid "Show follows similar to {0}"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr ""
@@ -3956,7 +4076,7 @@ msgstr ""
msgid "Something went wrong. Check your email and try again."
msgstr ""
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr ""
@@ -4022,7 +4142,7 @@ msgstr "ŠŃŠ“ŠæŠøŃŠ°ŃŠøŃŃ Š½Š° ŃŠµŠ¹ ŃŠæŠøŃŠ¾Šŗ"
#~ msgid "Subscribed"
#~ msgstr ""
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "ŠŃŠ¾ŠæŠ¾Š½Š¾Š²Š°Š½Ń ŠæŃŠ“ŠæŠøŃŠŗŠø"
@@ -4066,6 +4186,14 @@ msgstr ""
msgid "System log"
msgstr "ДиŃŃŠµŠ¼Š½ŠøŠ¹ жŃŃŠ½Š°Š»"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "ŠŠøŃоке"
@@ -4089,6 +4217,10 @@ msgstr "Умови"
msgid "Terms of Service"
msgstr "Умови ŠŠøŠŗŠ¾ŃŠøŃŃŠ°Š½Š½Ń"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -4114,7 +4246,7 @@ msgstr "ŠŠ¾Š»ŃŃŠøŠŗŃ заŃ
ŠøŃŃŃ Š°Š²ŃŠ¾ŃŃŃŠŗŠ¾Š³Š¾ ŠæŃŠ°Š²Š° пеŃ
msgid "The following steps will help customize your Bluesky experience."
msgstr ""
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "ŠŠ¾Š¶Š»ŠøŠ²Š¾ ŃŠµŠ¹ поŃŃ Š±ŃŠ»Š¾ виГалено."
@@ -4296,7 +4428,7 @@ msgstr ""
msgid "This name is already in use"
msgstr ""
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "Цей поŃŃ Š±ŃŠ»Š¾ виГалено."
@@ -4320,7 +4452,11 @@ msgstr ""
msgid "This warning is only available for posts with media attached."
msgstr "Це ŠæŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń Š“Š¾ŃŃŃŠæŠ½Šµ ŃŃŠ»ŃŠŗŠø Š“Š»Ń Š·Š°ŠæŠøŃŃŠ² Š· ŠæŃŠøŠŗŃŃŠæŠ»ŠµŠ½ŠøŠ¼Šø Š¼ŠµŠ“ŃŠ°-ŃŠ°Š¹Š»Š°Š¼Šø."
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "Це ŠæŃŠøŃ
Š¾Š²Š°Ń ŃŠµŠ¹ поŃŃ ŃŠ· Š²Š°ŃŠ¾Ń ŃŃŃŃŃŠŗŠø."
@@ -4337,6 +4473,10 @@ msgstr "Режим Š³Ńлок"
msgid "Threads Preferences"
msgstr ""
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "Š Š¾Š·ŠŗŃŠøŃŠø/ŃŃ
Š¾Š²Š°ŃŠø"
@@ -4345,9 +4485,9 @@ msgstr "Š Š¾Š·ŠŗŃŠøŃŠø/ŃŃ
Š¾Š²Š°ŃŠø"
msgid "Transformations"
msgstr "Š ŠµŠ“Š°Š³ŃŠ²Š°Š½Š½Ń"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "ŠŠµŃеклаŃŃŠø"
@@ -4416,15 +4556,24 @@ msgstr "ŠŠ° жалŃ, ви не Š²ŃŠ“ŠæŠ¾Š²ŃŠ“аŃŃŠµ вимогам ГлŃ
msgid "Unlike"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr ""
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "ŠŠµŃеŃŃŠ°ŃŠø ŃŠ³Š½Š¾ŃŃŠ²Š°ŃŠø"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "ŠŠµŃеŃŃŠ°ŃŠø ŃŠ³Š½Š¾ŃŃŠ²Š°ŃŠø"
@@ -4633,6 +4782,10 @@ msgstr ""
#~ msgid "We recommend \"For You\" by Skygaze:"
#~ msgstr ""
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr ""
@@ -4669,7 +4822,11 @@ msgstr "ŠŠø Š“ŃŠ¶Šµ ŃŠ°Š“Ń, ŃŠ¾ ви ŠæŃŠøŃГналиŃŃ!"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr ""
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "ŠŠ°ŃŃŠ¹Ńе, нам не вГалоŃŃ Š²ŠøŠŗŠ¾Š½Š°ŃŠø поŃŃŠŗ за Š²Š°Ńим Š·Š°ŠæŠøŃом. ŠŃŠ“Ń Š»Š°ŃŠŗŠ°, ŃŠæŃŠ¾Š±ŃŠ¹Ńе ŃŠµ ŃŠ°Š· ŃŠµŃез ŠŗŃŠ»Ńка Ń
вилин."
@@ -4690,7 +4847,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "Яка ŠæŃоблема Š· {collectionName}?"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "ŠÆŠŗ ŃŠæŃави?"
@@ -4715,11 +4872,11 @@ msgstr "Š„ŃŠ¾ може Š²ŃŠ“ŠæŠ¾Š²ŃŠ“Š°ŃŠø"
msgid "Wide"
msgstr "ŠØŠøŃŠ¾ŠŗŠµ"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "ŠŠ°ŠæŠøŃŠ°ŃŠø поŃŃ"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "ŠŠ°ŠæŠøŃŠ°ŃŠø Š²ŃŠ“ŠæŠ¾Š²ŃŠ“Ń"
@@ -4788,7 +4945,7 @@ msgstr "Š£ Š²Š°Ń Š½ŠµŠ¼Š°Ń Š·Š±ŠµŃŠµŠ¶ŠµŠ½ŠøŃ
ŃŃŃŃŃŠ¾Šŗ!"
msgid "You don't have any saved feeds."
msgstr "Š£ Š²Š°Ń Š½ŠµŠ¼Š°Ń Š·Š±ŠµŃŠµŠ¶ŠµŠ½ŠøŃ
ŃŃŃŃŃŠ¾Šŗ."
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "ŠŠø Š·Š°Š±Š»Š¾ŠŗŃŠ²Š°Š»Šø Š°Š²ŃŠ¾Ńа або Š°Š²ŃŠ¾Ń Š·Š°Š±Š»Š¾ŠŗŃŠ²Š°Š² ваŃ."
@@ -4828,6 +4985,10 @@ msgstr "ŠŠø ŃŠµ не ŃŃŠ²Š¾Ńили жоГного ŠæŠ°ŃŠ¾Š»Ń Š“Š»Ń Š·Š°
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "ŠŠø ŃŠµ не ŃŠ³Š½Š¾ŃŃŃŃŠµ жоГного Š¾Š±Š»Ńкового запиŃŃ. Щоб ŃŠ³Š½Š¾ŃŃŠ²Š°ŃŠø когоŃŃ, ŠæŠµŃŠµŠ¹Š“ŃŃŃ Š“Š¾ ŃŃ
ŠæŃŠ¾ŃŃŠ»Ń ŃŠ° вибеŃŃŃŃ Š¾ŠæŃŃŃ \"ŠŠ³Š½Š¾ŃŃŠ²Š°ŃŠø\" Ń Š¼ŠµŠ½Ń ŃŃ
Š¾Š±Š»ŃŠŗŠ¾Š²Š¾Š³Š¾ запиŃŃ."
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr ""
@@ -4836,11 +4997,11 @@ msgstr ""
msgid "You must be 18 years or older to enable adult content"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr ""
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr ""
@@ -4930,11 +5091,15 @@ msgstr ""
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "ŠŠ°ŃŃ ŠŗŠ¾Š“Šø Š·Š°ŠæŃŠ¾ŃŠµŠ½Š½Ń ŠæŃŠøŃ
овано, ŃŠŗŃо ви ŃŠ²ŃŠ¹ŃŠ»Šø за Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń ŠæŠ°ŃŠ¾Š»Ń Š“Š»Ń Š·Š°ŃŃŠ¾ŃŃŠ½ŠŗŃв"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr ""
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr ""
@@ -4961,7 +5126,7 @@ msgstr "ŠŠ°Ń ŠæŃŠ¾ŃŃŠ»Ń"
#~ msgid "Your profile and posts will not be visible to people visiting the Bluesky app or website without having an account and being logged in."
#~ msgstr ""
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr ""
diff --git a/src/locale/locales/zh-CN/messages.po b/src/locale/locales/zh-CN/messages.po
index aa7b24c9c6..c4447af264 100644
--- a/src/locale/locales/zh-CN/messages.po
+++ b/src/locale/locales/zh-CN/messages.po
@@ -76,7 +76,7 @@ msgid "A new version of the app is available. Please update to continue using th
msgstr "App ę°ēę¬å·²ååøļ¼čÆ·ę“ę°ä»„ē»§ē»ä½æēØć"
#: src/view/com/util/ViewHeader.tsx:83
-#: src/view/screens/Search/Search.tsx:624
+#: src/view/screens/Search/Search.tsx:647
msgid "Access navigation links and settings"
msgstr "访é®åƼčŖé¾ę„å设置"
@@ -127,6 +127,7 @@ msgstr "å·²åę¶å±č½č“¦ę·"
msgid "Account unmuted"
msgstr "å·²åę¶éč蓦ę·"
+#: src/components/dialogs/MutedWords.tsx:147
#: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -168,14 +169,22 @@ msgstr "ę·»å ē»č"
msgid "Add details to report"
msgstr "蔄å
åé¦čƦē»å
容"
-#: src/view/com/composer/Composer.tsx:446
+#: src/view/com/composer/Composer.tsx:453
msgid "Add link card"
msgstr "ę·»å é¾ę„å”ē"
-#: src/view/com/composer/Composer.tsx:451
+#: src/view/com/composer/Composer.tsx:458
msgid "Add link card:"
msgstr "ę·»å é¾ę„å”ē:"
+#: src/components/dialogs/MutedWords.tsx:140
+msgid "Add mute word for configured settings"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:74
+msgid "Add muted words and tags"
+msgstr ""
+
#: src/view/com/modals/ChangeHandle.tsx:417
msgid "Add the following DNS record to your domain:"
msgstr "å°ä»„äøDNSč®°å½ę·»å å°ä½ ēåå:"
@@ -295,7 +304,7 @@ msgstr "App äøēØåÆē 设置"
msgid "App Passwords"
msgstr "App äøēØåÆē "
-#: src/view/com/util/forms/PostDropdownBtn.tsx:279
+#: src/view/com/util/forms/PostDropdownBtn.tsx:295
msgid "Appeal content warning"
msgstr "ē³čÆå
容č¦å"
@@ -319,15 +328,16 @@ msgstr "å¤č§"
msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "ä½ ē”®å®č¦å é¤čæę” App äøēØåÆē \"{name}\"ļ¼"
-#: src/view/com/composer/Composer.tsx:143
+#: src/view/com/composer/Composer.tsx:150
msgid "Are you sure you'd like to discard this draft?"
msgstr "ä½ ē”®å®č¦äø¢å¼ę¤č稿åļ¼"
+#: src/components/dialogs/MutedWords.tsx:233
#: src/view/screens/ProfileList.tsx:365
msgid "Are you sure?"
msgstr "ä½ ē”®å®åļ¼"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:262
+#: src/view/com/util/forms/PostDropdownBtn.tsx:278
msgid "Are you sure? This cannot be undone."
msgstr "ä½ ē”®å®åļ¼ę¤ęä½ę ę³ę¤éć"
@@ -349,15 +359,15 @@ msgstr "čŗęÆä½åęéč²ę
ē裸ä½ć"
#: src/view/com/auth/login/LoginForm.tsx:259
#: src/view/com/auth/login/SetNewPasswordForm.tsx:179
#: src/view/com/modals/report/InputIssueDetails.tsx:46
-#: src/view/com/post-thread/PostThread.tsx:471
-#: src/view/com/post-thread/PostThread.tsx:521
-#: src/view/com/post-thread/PostThread.tsx:529
+#: src/view/com/post-thread/PostThread.tsx:472
+#: src/view/com/post-thread/PostThread.tsx:522
+#: src/view/com/post-thread/PostThread.tsx:530
#: src/view/com/profile/ProfileHeader.tsx:649
#: src/view/com/util/ViewHeader.tsx:81
msgid "Back"
msgstr "čæå"
-#: src/view/com/post-thread/PostThread.tsx:479
+#: src/view/com/post-thread/PostThread.tsx:480
msgctxt "action"
msgid "Back"
msgstr "čæå"
@@ -405,7 +415,7 @@ msgstr "å±č½čæäøŖå蔨"
msgid "Blocked"
msgstr "å·²å±č½"
-#: src/view/screens/Moderation.tsx:123
+#: src/view/screens/Moderation.tsx:142
msgid "Blocked accounts"
msgstr "å·²å±č½č“¦ę·"
@@ -464,7 +474,7 @@ msgstr "Bluesky äøŗå
¬ä¼čēć"
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
msgstr "Bluesky 使ēØé请å¶ę„ęé ę“å„åŗ·ē社群ēÆå¢ć å¦ęä½ äøč®¤čÆę„ęé请ē ēäŗŗļ¼ä½ åÆä»„å
唫åå¹¶ęäŗ¤å蔄å蔨ļ¼ę们ä¼å°½åæ«å®”ę øå¹¶åéé请ē ć"
-#: src/view/screens/Moderation.tsx:226
+#: src/view/screens/Moderation.tsx:245
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
msgstr "Bluesky äøä¼åęŖē»å½ēēØę·ę¾ē¤ŗä½ ēäøŖäŗŗčµęååøåćä½å
¶ä»åŗēØåÆč½äøä¼éµē
§ę¤čÆ·ę±ļ¼čæę ę³ē”®äæä½ ē蓦ę·éē§ć"
@@ -516,8 +526,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "åŖč½å
å«åęÆćę°åćē©ŗę ¼ćē “ęå·åäøåēŗæć éæåŗ¦åæ
é”»č³å° 4 äøŖå符ļ¼ä½äøč¶
čæ 32 äøŖå符ć"
#: src/components/Prompt.tsx:91
-#: src/view/com/composer/Composer.tsx:300
-#: src/view/com/composer/Composer.tsx:305
+#: src/view/com/composer/Composer.tsx:307
+#: src/view/com/composer/Composer.tsx:312
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/ChangePassword.tsx:265
@@ -531,7 +541,7 @@ msgstr "åŖč½å
å«åęÆćę°åćē©ŗę ¼ćē “ęå·åäøåēŗæć éæåŗ¦
#: src/view/com/modals/VerifyEmail.tsx:247
#: src/view/com/modals/VerifyEmail.tsx:253
#: src/view/com/modals/Waitlist.tsx:142
-#: src/view/screens/Search/Search.tsx:693
+#: src/view/screens/Search/Search.tsx:716
#: src/view/shell/desktop/Search.tsx:238
msgid "Cancel"
msgstr "åę¶"
@@ -678,7 +688,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "ęø
é¤ęęę°ę®ļ¼å¹¶éåÆļ¼"
#: src/view/com/util/forms/SearchInput.tsx:88
-#: src/view/screens/Search/Search.tsx:674
+#: src/view/screens/Search/Search.tsx:697
msgid "Clear search query"
msgstr "ęø
é¤ęē“¢åå²č®°å½"
@@ -686,6 +696,11 @@ msgstr "ęø
é¤ęē“¢åå²č®°å½"
msgid "click here"
msgstr "ē¹å»čæé"
+#: src/components/RichText.tsx:189
+#: src/components/TagMenu/index.web.tsx:125
+msgid "Click here to open tag menu for {tag}"
+msgstr ""
+
#: src/screens/Onboarding/index.tsx:35
msgid "Climate"
msgstr "ę°č±”"
@@ -716,11 +731,15 @@ msgstr "å
³éå¾ē"
msgid "Close image viewer"
msgstr "å
³éå¾ēę„ēåØ"
-#: src/view/shell/index.web.tsx:49
+#: src/view/shell/index.web.tsx:51
msgid "Close navigation footer"
msgstr "å
³é导čŖé”µč"
-#: src/view/shell/index.web.tsx:50
+#: src/components/TagMenu/index.tsx:266
+msgid "Close this dialog"
+msgstr ""
+
+#: src/view/shell/index.web.tsx:52
msgid "Closes bottom navigation bar"
msgstr "å
³éåŗę "
@@ -728,7 +747,7 @@ msgstr "å
³éåŗę "
msgid "Closes password update alert"
msgstr "å
³éåÆē ę“ę°č¦å"
-#: src/view/com/composer/Composer.tsx:302
+#: src/view/com/composer/Composer.tsx:309
msgid "Closes post composer and discards post draft"
msgstr "å
³éåøåē¼č¾é”µå¹¶äø¢å¼č稿"
@@ -761,7 +780,7 @@ msgstr "å®ęå¼åƼ并å¼å§ä½æēØä½ ē蓦ę·"
msgid "Complete the challenge"
msgstr ""
-#: src/view/com/composer/Composer.tsx:417
+#: src/view/com/composer/Composer.tsx:424
msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length"
msgstr "ę°ååøåēéæåŗ¦ęå¤äøŗ {MAX_GRAPHEME_LENGTH} äøŖå符"
@@ -825,7 +844,7 @@ msgstr "čæę„äø..."
msgid "Contact support"
msgstr "čē³»ęÆę"
-#: src/view/screens/Moderation.tsx:81
+#: src/view/screens/Moderation.tsx:83
msgid "Content filtering"
msgstr "å
容čæę»¤"
@@ -891,7 +910,7 @@ msgstr "å·²å¤å¶ę建ēę¬å·č³åŖč““ęæ"
#: src/view/com/modals/AddAppPasswords.tsx:76
#: src/view/com/modals/InviteCodes.tsx:152
-#: src/view/com/util/forms/PostDropdownBtn.tsx:141
+#: src/view/com/util/forms/PostDropdownBtn.tsx:143
msgid "Copied to clipboard"
msgstr "å·²å¤å¶č³åŖč““ęæ"
@@ -907,7 +926,7 @@ msgstr "å¤å¶"
msgid "Copy link to list"
msgstr "å¤å¶å蔨é¾ę„"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
msgid "Copy link to post"
msgstr "å¤å¶åøåé¾ę„"
@@ -915,7 +934,7 @@ msgstr "å¤å¶åøåé¾ę„"
msgid "Copy link to profile"
msgstr "å¤å¶äøŖäŗŗčµęé¾ę„"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:168
+#: src/view/com/util/forms/PostDropdownBtn.tsx:170
msgid "Copy post text"
msgstr "å¤å¶åøåęå"
@@ -971,7 +990,7 @@ msgstr "ē± <0/> å建"
msgid "Created by you"
msgstr "ē±ä½ å建"
-#: src/view/com/composer/Composer.tsx:448
+#: src/view/com/composer/Composer.tsx:455
msgid "Creates a card with a thumbnail. The card links to {url}"
msgstr "å建带ę缩ē„å¾ēå”ēć评å”ēé¾ę„å° {url}"
@@ -1048,11 +1067,11 @@ msgstr "å é¤ęē蓦ę·"
msgid "Delete My Accountā¦"
msgstr "å é¤ęē蓦ę·ā¦"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:257
+#: src/view/com/util/forms/PostDropdownBtn.tsx:273
msgid "Delete post"
msgstr "å é¤åøå"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:261
+#: src/view/com/util/forms/PostDropdownBtn.tsx:277
msgid "Delete this post?"
msgstr "å é¤čæę”åøåļ¼"
@@ -1075,7 +1094,7 @@ msgstr "ęčæ°"
#~ msgid "Developer Tools"
#~ msgstr "å¼åč
å·„å
·"
-#: src/view/com/composer/Composer.tsx:211
+#: src/view/com/composer/Composer.tsx:218
msgid "Did you want to say anything?"
msgstr "ęä»ä¹ę³čÆ“ēåļ¼"
@@ -1083,15 +1102,15 @@ msgstr "ęä»ä¹ę³čÆ“ēåļ¼"
msgid "Dim"
msgstr "ęę·”"
-#: src/view/com/composer/Composer.tsx:144
+#: src/view/com/composer/Composer.tsx:151
msgid "Discard"
msgstr "äø¢å¼"
-#: src/view/com/composer/Composer.tsx:138
+#: src/view/com/composer/Composer.tsx:145
msgid "Discard draft"
msgstr "äø¢å¼č稿"
-#: src/view/screens/Moderation.tsx:207
+#: src/view/screens/Moderation.tsx:226
msgid "Discourage apps from showing my account to logged-out users"
msgstr "é»ę¢åŗēØåęŖē»å½ēØę·ę¾ē¤ŗęē蓦ę·"
@@ -1170,7 +1189,7 @@ msgstr ""
msgid "Download CAR file"
msgstr ""
-#: src/view/com/composer/text-input/TextInput.web.tsx:247
+#: src/view/com/composer/text-input/TextInput.web.tsx:249
msgid "Drop to add images"
msgstr "ęę¾å³åÆę·»å å¾ē"
@@ -1242,6 +1261,7 @@ msgstr "ē¼č¾čµę"
msgid "Edit Profile"
msgstr "ē¼č¾čµę"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:59
#: src/view/screens/Feeds.tsx:355
msgid "Edit Saved Feeds"
msgstr "ē¼č¾äæåēäæ”ęÆęµ"
@@ -1324,6 +1344,11 @@ msgstr "ē»ęäæ”ęÆęµ"
msgid "Enter a name for this App Password"
msgstr "äøŗę¤ App äøēØåÆē å½å"
+#: src/components/dialogs/MutedWords.tsx:87
+#: src/components/dialogs/MutedWords.tsx:88
+msgid "Enter a word or tag"
+msgstr ""
+
#: src/view/com/modals/VerifyEmail.tsx:105
msgid "Enter Confirmation Code"
msgstr "č¾å
„éŖčÆē "
@@ -1373,7 +1398,7 @@ msgstr "č¾å
„ä½ ēēØę·åååÆē "
msgid "Error receiving captcha response."
msgstr ""
-#: src/view/screens/Search/Search.tsx:109
+#: src/view/screens/Search/Search.tsx:110
msgid "Error:"
msgstr "é误ļ¼"
@@ -1444,7 +1469,7 @@ msgstr "å建 App äøēØåÆē 失蓄ć"
msgid "Failed to create the list. Check your internet connection and try again."
msgstr "ę ę³å建å蔨ć请ę£ę„ä½ ēäŗčē½čæę„å¹¶éčÆć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:108
+#: src/view/com/util/forms/PostDropdownBtn.tsx:110
msgid "Failed to delete post, please try again"
msgstr "ę ę³å é¤åøåļ¼čÆ·éčÆ"
@@ -1466,8 +1491,8 @@ msgid "Feed offline"
msgstr "äæ”ęÆęµå·²ē¦»ēŗæ"
#: src/view/com/feeds/FeedPage.tsx:143
-msgid "Feed Preferences"
-msgstr "äæ”ęÆęµé¦é锹"
+#~ msgid "Feed Preferences"
+#~ msgstr "äæ”ęÆęµé¦é锹"
#: src/view/shell/desktop/RightNav.tsx:61
#: src/view/shell/Drawer.tsx:311
@@ -1511,11 +1536,11 @@ msgstr "ęē»ē”®å®"
msgid "Find accounts to follow"
msgstr "寻ę¾äøäŗč“¦ę·å
³ę³Ø"
-#: src/view/screens/Search/Search.tsx:439
+#: src/view/screens/Search/Search.tsx:440
msgid "Find users on Bluesky"
msgstr "寻ę¾äøäŗę£åØä½æēØ Bluesky ēēØę·"
-#: src/view/screens/Search/Search.tsx:437
+#: src/view/screens/Search/Search.tsx:438
msgid "Find users with the search tool on the right"
msgstr "使ēØå³ä¾§ēå·„å
·ę„ęē“¢ēØę·"
@@ -1612,6 +1637,7 @@ msgid "Following {0}"
msgstr "ę£åØå
³ę³Ø {0}"
#: src/Navigation.tsx:248
+#: src/view/com/home/HomeHeaderLayout.web.tsx:45
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83
#: src/view/screens/PreferencesFollowingFeed.tsx:104
#: src/view/screens/Settings/index.tsx:543
@@ -1651,7 +1677,7 @@ msgstr "åæč®°åÆē "
msgid "Forgot Password"
msgstr "åæč®°åÆē "
-#: src/view/com/posts/FeedItem.tsx:187
+#: src/view/com/posts/FeedItem.tsx:189
msgctxt "from-feed"
msgid "From <0/>"
msgstr "ę„čŖ <0/>"
@@ -1684,7 +1710,7 @@ msgstr "čæå"
msgid "Go back to previous step"
msgstr "čæåäøäøę„"
-#: src/view/screens/Search/Search.tsx:724
+#: src/view/screens/Search/Search.tsx:747
#: src/view/shell/desktop/Search.tsx:262
msgid "Go to @{queryMaybeHandle}"
msgstr "č½¬å° @{queryMaybeHandle}"
@@ -1701,6 +1727,10 @@ msgstr "转å°äøäøäøŖ"
msgid "Handle"
msgstr "ēØę·čÆå«ē¬¦"
+#: src/components/RichText.tsx:188
+msgid "Hashtag: {tag}"
+msgstr ""
+
#: src/view/com/auth/create/CreateAccount.tsx:208
msgid "Having trouble?"
msgstr "ä»»ä½ēé®ļ¼"
@@ -1739,7 +1769,7 @@ msgctxt "action"
msgid "Hide"
msgstr "éč"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+#: src/view/com/util/forms/PostDropdownBtn.tsx:232
msgid "Hide post"
msgstr "éčåøå"
@@ -1748,7 +1778,7 @@ msgstr "éčåøå"
msgid "Hide the content"
msgstr "éčå
容"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:220
+#: src/view/com/util/forms/PostDropdownBtn.tsx:236
msgid "Hide this post?"
msgstr "éččæę”åøåļ¼"
@@ -1897,7 +1927,7 @@ msgstr "č¾å
„ä½ ēåÆē "
msgid "Input your user handle"
msgstr "č¾å
„ä½ ēēØę·čÆå«ē¬¦"
-#: src/view/com/post-thread/PostThreadItem.tsx:224
+#: src/view/com/post-thread/PostThreadItem.tsx:226
msgid "Invalid or unsupported post record"
msgstr "åøåč®°å½ę ęęäøåęÆę"
@@ -1999,7 +2029,7 @@ msgstr "äŗč§£čƦę
"
msgid "Learn more about this warning"
msgstr "äŗč§£å
³äŗčæäøŖč¦åēę“å¤čƦę
"
-#: src/view/screens/Moderation.tsx:243
+#: src/view/screens/Moderation.tsx:262
msgid "Learn more about what is public on Bluesky."
msgstr "äŗč§£ęå
³ Bluesky å
¬å¼å
容ēę“å¤čƦę
ć"
@@ -2075,7 +2105,7 @@ msgstr "ē¹čµä½ ēåøå"
msgid "Likes"
msgstr "ē¹čµ"
-#: src/view/com/post-thread/PostThreadItem.tsx:181
+#: src/view/com/post-thread/PostThreadItem.tsx:183
msgid "Likes on this post"
msgstr "ē¹čµčæę”åøå"
@@ -2132,7 +2162,7 @@ msgstr "å č½½ę“å¤åøå"
msgid "Load new notifications"
msgstr "å č½½ę°ēéē„"
-#: src/view/com/feeds/FeedPage.tsx:181
+#: src/view/com/feeds/FeedPage.tsx:115
#: src/view/screens/Profile.tsx:440
#: src/view/screens/ProfileFeed.tsx:495
#: src/view/screens/ProfileList.tsx:681
@@ -2158,7 +2188,7 @@ msgstr "ę„åæ"
msgid "Log out"
msgstr "ē»åŗ"
-#: src/view/screens/Moderation.tsx:136
+#: src/view/screens/Moderation.tsx:155
msgid "Logged-out visibility"
msgstr "ęŖē»å½ēØę·åÆč§ę§"
@@ -2170,6 +2200,10 @@ msgstr "ē»å½ęŖååŗē蓦ę·"
msgid "Make sure this is where you intend to go!"
msgstr "请甮认ļ¼"
+#: src/components/dialogs/MutedWords.tsx:71
+msgid "Manage your muted words and tags"
+msgstr ""
+
#: src/view/com/auth/create/Step2.tsx:118
msgid "May not be longer than 253 characters"
msgstr ""
@@ -2191,7 +2225,7 @@ msgid "Mentioned users"
msgstr "ęå°ēēØę·"
#: src/view/com/util/ViewHeader.tsx:81
-#: src/view/screens/Search/Search.tsx:623
+#: src/view/screens/Search/Search.tsx:646
msgid "Menu"
msgstr "čå"
@@ -2200,7 +2234,7 @@ msgid "Message from server: {0}"
msgstr "ę„čŖęå”åØēäæ”ęÆļ¼{0}"
#: src/Navigation.tsx:115
-#: src/view/screens/Moderation.tsx:64
+#: src/view/screens/Moderation.tsx:66
#: src/view/screens/Settings/index.tsx:625
#: src/view/shell/desktop/LeftNav.tsx:397
#: src/view/shell/Drawer.tsx:511
@@ -2231,7 +2265,7 @@ msgstr "éå¶å蔨已å建"
msgid "Moderation list updated"
msgstr "éå¶å蔨已ę“ę°"
-#: src/view/screens/Moderation.tsx:95
+#: src/view/screens/Moderation.tsx:114
msgid "Moderation lists"
msgstr "éå¶å蔨"
@@ -2258,7 +2292,7 @@ msgstr "ę“å¤äæ”ęÆęµ"
msgid "More options"
msgstr "ę“å¤é锹"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:299
+#: src/view/com/util/forms/PostDropdownBtn.tsx:315
msgid "More post options"
msgstr "ę“å¤åøåé锹"
@@ -2270,6 +2304,14 @@ msgstr "ęå¤ē¹čµä¼å
"
msgid "Must be at least 3 characters"
msgstr ""
+#: src/components/TagMenu/index.tsx:253
+msgid "Mute"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:91
+msgid "Mute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:327
msgid "Mute Account"
msgstr "éč蓦ę·"
@@ -2278,6 +2320,18 @@ msgstr "éč蓦ę·"
msgid "Mute accounts"
msgstr "éč蓦ę·"
+#: src/components/TagMenu/index.tsx:211
+msgid "Mute all {tag} posts"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:131
+msgid "Mute in tags only"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:116
+msgid "Mute in text & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:491
msgid "Mute list"
msgstr "éčå蔨"
@@ -2290,15 +2344,27 @@ msgstr "éččæäŗč“¦ę·ļ¼"
msgid "Mute this List"
msgstr "éččæäøŖå蔨"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/dialogs/MutedWords.tsx:109
+msgid "Mute this word in post text and tags"
+msgstr ""
+
+#: src/components/dialogs/MutedWords.tsx:124
+msgid "Mute this word in tags only"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Mute thread"
msgstr "éč讨论串"
+#: src/view/com/util/forms/PostDropdownBtn.tsx:216
+msgid "Mute words & tags"
+msgstr ""
+
#: src/view/com/lists/ListCard.tsx:102
msgid "Muted"
msgstr "å·²éč"
-#: src/view/screens/Moderation.tsx:109
+#: src/view/screens/Moderation.tsx:128
msgid "Muted accounts"
msgstr "å·²éč蓦ę·"
@@ -2311,6 +2377,10 @@ msgstr "å·²éč蓦ę·"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "å·²éčē蓦ę·å°äøä¼åØä½ ēéē„ęę¶é“ēŗæäøę¾ē¤ŗļ¼č¢«éč蓦ę·å°äøä¼ę¶å°éē„ć"
+#: src/view/screens/Moderation.tsx:100
+msgid "Muted words & tags"
+msgstr ""
+
#: src/view/screens/ProfileList.tsx:277
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "被éčē蓦ę·å°äøä¼å¾ē„ä½ å·²å°ä»éčļ¼å·²éčē蓦ę·å°äøä¼åØä½ ēéē„ęę¶é“ēŗæäøę¾ē¤ŗć"
@@ -2374,6 +2444,10 @@ msgstr "ę°øčæäøä¼å¤±å»åÆ¹ä½ ēå
³ę³Øč
åę°ę®ē访é®ć"
msgid "Never lose access to your followers or data."
msgstr "ę°øčæäøä¼å¤±å»åÆ¹ä½ ēå
³ę³Øč
ęę°ę®ē访é®ć"
+#: src/components/dialogs/MutedWords.tsx:244
+msgid "Nevermind"
+msgstr ""
+
#: src/view/screens/Lists.tsx:76
msgctxt "action"
msgid "New"
@@ -2395,7 +2469,7 @@ msgstr "ę°åÆē "
msgid "New Password"
msgstr "ę°åÆē "
-#: src/view/com/feeds/FeedPage.tsx:192
+#: src/view/com/feeds/FeedPage.tsx:126
msgctxt "action"
msgid "New post"
msgstr "ę°åøå"
@@ -2480,8 +2554,8 @@ msgid "No results found for \"{query}\""
msgstr "ęŖę¾å°\"{query}\"ēē»ę"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127
-#: src/view/screens/Search/Search.tsx:280
-#: src/view/screens/Search/Search.tsx:308
+#: src/view/screens/Search/Search.tsx:281
+#: src/view/screens/Search/Search.tsx:309
msgid "No results found for {query}"
msgstr "ęŖę¾å° {query} ēē»ę"
@@ -2507,7 +2581,7 @@ msgstr "ęŖę¾å°"
msgid "Not right now"
msgstr "äøęÆē°åØ"
-#: src/view/screens/Moderation.tsx:233
+#: src/view/screens/Moderation.tsx:252
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
msgstr "注ęļ¼Bluesky ęÆäøäøŖå¼ę¾ēå
Œ
±ē½ē»ćę¤č®¾ē½®é”¹ä»
éå¶ä½ ēå
å®¹åØ Bluesky åŗēØåē½ē«äøēåÆč§ę§ļ¼å
¶ä»åŗēØåÆč½äøå°ä»ę¤č®¾ē½®é”¹ļ¼ä»åÆč½ä¼åęŖē»å½ēēØę·ę¾ē¤ŗä½ ēåØęć"
@@ -2545,7 +2619,7 @@ msgstr "ęę§ēåå¤ä¼å
"
msgid "Onboarding reset"
msgstr "éę°å¼å§å¼åƼęµēØ"
-#: src/view/com/composer/Composer.tsx:375
+#: src/view/com/composer/Composer.tsx:382
msgid "One or more images is missing alt text."
msgstr "č³å°ęäøå¼ å¾ē缺失äŗęæä»£ęåć"
@@ -2562,8 +2636,12 @@ msgstr "Oopsļ¼"
msgid "Open"
msgstr "ęå¼"
-#: src/view/com/composer/Composer.tsx:470
-#: src/view/com/composer/Composer.tsx:471
+#: src/view/screens/Moderation.tsx:75
+msgid "Open content filtering settings"
+msgstr ""
+
+#: src/view/com/composer/Composer.tsx:477
+#: src/view/com/composer/Composer.tsx:478
msgid "Open emoji picker"
msgstr "ęå¼ emoji éę©åØ"
@@ -2571,6 +2649,10 @@ msgstr "ęå¼ emoji éę©åØ"
msgid "Open links with in-app browser"
msgstr "åØå
ē½®ęµč§åØäøęå¼é¾ę„"
+#: src/view/screens/Moderation.tsx:92
+msgid "Open muted words settings"
+msgstr ""
+
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49
msgid "Open navigation"
msgstr "ęå¼åƼčŖ"
@@ -2647,6 +2729,7 @@ msgstr "ęå¼éå¶č®¾ē½®"
msgid "Opens password reset form"
msgstr "ęå¼åÆē éē½®ē³čÆ·"
+#: src/view/com/home/HomeHeaderLayout.web.tsx:60
#: src/view/screens/Feeds.tsx:356
msgid "Opens screen to edit Saved Feeds"
msgstr "ęå¼ēØäŗē¼č¾å·²äæåäæ”ęÆęµēēé¢"
@@ -2822,7 +2905,7 @@ msgstr "请åčÆęä»¬ä½ č®¤äøŗę¤å
容č¦å被é误设置ēåå ļ¼"
msgid "Please Verify Your Email"
msgstr "请éŖčÆä½ ēēµåé®ē®±"
-#: src/view/com/composer/Composer.tsx:215
+#: src/view/com/composer/Composer.tsx:222
msgid "Please wait for your link card to finish loading"
msgstr "请ēå¾
ä½ ēé¾ę„å”ēå č½½å®ę"
@@ -2834,8 +2917,8 @@ msgstr "ęæę²»"
msgid "Porn"
msgstr "č²ę
å
容"
-#: src/view/com/composer/Composer.tsx:350
-#: src/view/com/composer/Composer.tsx:358
+#: src/view/com/composer/Composer.tsx:357
+#: src/view/com/composer/Composer.tsx:365
msgctxt "action"
msgid "Post"
msgstr "ååø"
@@ -2845,7 +2928,7 @@ msgctxt "description"
msgid "Post"
msgstr "ååø"
-#: src/view/com/post-thread/PostThreadItem.tsx:173
+#: src/view/com/post-thread/PostThreadItem.tsx:175
msgid "Post by {0}"
msgstr "ååøč
{0}"
@@ -2855,11 +2938,11 @@ msgstr "ååøč
{0}"
msgid "Post by @{0}"
msgstr "ååøč
@{0}"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:88
+#: src/view/com/util/forms/PostDropdownBtn.tsx:90
msgid "Post deleted"
msgstr "å·²å é¤åøå"
-#: src/view/com/post-thread/PostThread.tsx:461
+#: src/view/com/post-thread/PostThread.tsx:462
msgid "Post hidden"
msgstr "å·²éčåøå"
@@ -2871,14 +2954,22 @@ msgstr "åøåčÆčØ"
msgid "Post Languages"
msgstr "åøåčÆčØ"
-#: src/view/com/post-thread/PostThread.tsx:513
+#: src/view/com/post-thread/PostThread.tsx:514
msgid "Post not found"
msgstr "ę ę³ę¾å°åøå"
+#: src/components/TagMenu/index.tsx:257
+msgid "posts"
+msgstr ""
+
#: src/view/screens/Profile.tsx:180
msgid "Posts"
msgstr "åøå"
+#: src/components/dialogs/MutedWords.tsx:77
+msgid "Posts can be muted based on their text, their tags, or both."
+msgstr ""
+
#: src/view/com/posts/FeedErrorMessage.tsx:64
msgid "Posts hidden"
msgstr "å·²éčåøå"
@@ -2943,11 +3034,11 @@ msgstr "å
¬å¼äøåÆå
±äŗ«ēę¹ééčęå±č½å蔨ć"
msgid "Public, shareable lists which can drive feeds."
msgstr "å
¬å¼äøåÆå
±äŗ«ēå蔨ļ¼åÆä½äøŗäæ”ęÆęµä½æēØć"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish post"
msgstr "ååøåøå"
-#: src/view/com/composer/Composer.tsx:335
+#: src/view/com/composer/Composer.tsx:342
msgid "Publish reply"
msgstr "ååøåå¤"
@@ -2981,6 +3072,7 @@ msgstr "ęØčäæ”ęÆęµ"
msgid "Recommended Users"
msgstr "ęØčēēØę·"
+#: src/components/dialogs/MutedWords.tsx:249
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/SelfLabel.tsx:83
#: src/view/com/modals/UserAddRemoveLists.tsx:219
@@ -3018,6 +3110,10 @@ msgstr "å é¤å¾ē"
msgid "Remove image preview"
msgstr "å é¤å¾ēé¢č§"
+#: src/components/dialogs/MutedWords.tsx:294
+msgid "Remove mute word from your list"
+msgstr ""
+
#: src/view/com/modals/Repost.tsx:47
msgid "Remove repost"
msgstr "å é¤č½¬å"
@@ -3052,7 +3148,7 @@ msgstr "åå¤"
msgid "Replies to this thread are disabled"
msgstr "对ę¤č®Øč®ŗäø²ēåå¤å·²č¢«ē¦ēØ"
-#: src/view/com/composer/Composer.tsx:348
+#: src/view/com/composer/Composer.tsx:355
msgctxt "action"
msgid "Reply"
msgstr "åå¤"
@@ -3062,7 +3158,7 @@ msgid "Reply Filters"
msgstr "åå¤čæę»¤åØ"
#: src/view/com/post/Post.tsx:167
-#: src/view/com/posts/FeedItem.tsx:285
+#: src/view/com/posts/FeedItem.tsx:287
msgctxt "description"
msgid "Reply to <0/>"
msgstr "åå¤ <0/>"
@@ -3084,7 +3180,7 @@ msgid "Report List"
msgstr "äø¾ę„å蔨"
#: src/view/com/modals/report/SendReportButton.tsx:37
-#: src/view/com/util/forms/PostDropdownBtn.tsx:239
+#: src/view/com/util/forms/PostDropdownBtn.tsx:255
msgid "Report post"
msgstr "äø¾ę„åøå"
@@ -3109,11 +3205,11 @@ msgstr "转åęå¼ēØåøå"
msgid "Reposted By"
msgstr "转å"
-#: src/view/com/posts/FeedItem.tsx:205
+#: src/view/com/posts/FeedItem.tsx:207
msgid "Reposted by {0}"
msgstr "ē± {0} 转å"
-#: src/view/com/posts/FeedItem.tsx:222
+#: src/view/com/posts/FeedItem.tsx:224
msgid "Reposted by <0/>"
msgstr "ē± <0/> 转å"
@@ -3121,7 +3217,7 @@ msgstr "ē± <0/> 转å"
msgid "reposted your post"
msgstr "转åä½ ēåøå"
-#: src/view/com/post-thread/PostThreadItem.tsx:186
+#: src/view/com/post-thread/PostThreadItem.tsx:188
msgid "Reposts of this post"
msgstr "转åčæę”åøå"
@@ -3272,9 +3368,9 @@ msgstr "ę»åØå°é”¶éØ"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:67
#: src/view/com/util/forms/SearchInput.tsx:79
-#: src/view/screens/Search/Search.tsx:418
-#: src/view/screens/Search/Search.tsx:645
-#: src/view/screens/Search/Search.tsx:663
+#: src/view/screens/Search/Search.tsx:419
+#: src/view/screens/Search/Search.tsx:668
+#: src/view/screens/Search/Search.tsx:686
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:324
#: src/view/shell/desktop/Search.tsx:214
@@ -3284,11 +3380,19 @@ msgstr "ę»åØå°é”¶éØ"
msgid "Search"
msgstr "ęē“¢"
-#: src/view/screens/Search/Search.tsx:712
+#: src/view/screens/Search/Search.tsx:735
#: src/view/shell/desktop/Search.tsx:255
msgid "Search for \"{query}\""
msgstr "ęē“¢ \"{query}\""
+#: src/components/TagMenu/index.tsx:145
+msgid "Search for all posts by @{authorHandle} with tag {tag}"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:90
+msgid "Search for all posts with tag {tag}"
+msgstr ""
+
#: src/view/com/auth/LoggedOut.tsx:104
#: src/view/com/auth/LoggedOut.tsx:105
#: src/view/com/modals/ListAddRemoveUsers.tsx:70
@@ -3299,6 +3403,22 @@ msgstr "ęē“¢ēØę·"
msgid "Security Step Required"
msgstr "ęéēå®å
Øę„éŖ¤"
+#: src/components/TagMenu/index.web.tsx:50
+msgid "See {truncatedTag} posts"
+msgstr ""
+
+#: src/components/TagMenu/index.web.tsx:67
+msgid "See {truncatedTag} posts by user"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:128
+msgid "See <0>{tag}0> posts"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:189
+msgid "See <0>{tag}0> posts by this user"
+msgstr ""
+
#: src/view/screens/SavedFeeds.tsx:163
msgid "See this guide"
msgstr "ę„ēęå"
@@ -3504,7 +3624,7 @@ msgid "Share"
msgstr "åäŗ«"
#: src/view/com/profile/ProfileHeader.tsx:295
-#: src/view/com/util/forms/PostDropdownBtn.tsx:182
+#: src/view/com/util/forms/PostDropdownBtn.tsx:184
#: src/view/screens/ProfileList.tsx:418
msgid "Share"
msgstr "åäŗ«"
@@ -3537,9 +3657,9 @@ msgstr "ę¾ē¤ŗę„čŖ {0} ēåµå
„å
容"
msgid "Show follows similar to {0}"
msgstr "ę¾ē¤ŗē±»ä¼¼äŗ {0} ēå
³ę³Øč
"
-#: src/view/com/post-thread/PostThreadItem.tsx:532
-#: src/view/com/post/Post.tsx:196
-#: src/view/com/posts/FeedItem.tsx:359
+#: src/view/com/post-thread/PostThreadItem.tsx:538
+#: src/view/com/post/Post.tsx:198
+#: src/view/com/posts/FeedItem.tsx:363
msgid "Show More"
msgstr "ę¾ē¤ŗę“å¤"
@@ -3707,7 +3827,7 @@ msgstr "ēØåŗå¼å"
msgid "Something went wrong. Check your email and try again."
msgstr "åŗäŗē¹é®é¢ļ¼čÆ·ę£ę„ä½ ēēµåé®ē®±å¹¶éčÆć"
-#: src/App.native.tsx:61
+#: src/App.native.tsx:63
msgid "Sorry! Your session expired. Please log in again."
msgstr "å¾ę±ęļ¼ä½ ēä¼čÆå·²čæęļ¼čÆ·éę°ē»å½ć"
@@ -3765,7 +3885,7 @@ msgstr "订é
{0} äæ”ęÆęµ"
msgid "Subscribe to this list"
msgstr "订é
čæäøŖå蔨"
-#: src/view/screens/Search/Search.tsx:373
+#: src/view/screens/Search/Search.tsx:374
msgid "Suggested Follows"
msgstr "ęØčēå
³ę³Øč
"
@@ -3809,6 +3929,14 @@ msgstr "ē³»ē»"
msgid "System log"
msgstr "ē³»ē»ę„åæ"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "tag"
+msgstr ""
+
+#: src/components/TagMenu/index.tsx:74
+msgid "Tag menu: {tag}"
+msgstr ""
+
#: src/view/com/modals/crop-image/CropImage.web.tsx:112
msgid "Tall"
msgstr "é«"
@@ -3832,6 +3960,10 @@ msgstr "ę”款"
msgid "Terms of Service"
msgstr "ęå”ę”款"
+#: src/components/dialogs/MutedWords.tsx:288
+msgid "text"
+msgstr ""
+
#: src/view/com/modals/AppealLabel.tsx:70
#: src/view/com/modals/report/InputIssueDetails.tsx:51
msgid "Text input field"
@@ -3857,7 +3989,7 @@ msgstr "ēę许åÆå·²čæē§»č³ <0/>"
msgid "The following steps will help customize your Bluesky experience."
msgstr "仄äøę„éŖ¤å°åø®å©å®å¶ä½ ē Bluesky ä½éŖć"
-#: src/view/com/post-thread/PostThread.tsx:516
+#: src/view/com/post-thread/PostThread.tsx:517
msgid "The post may have been deleted."
msgstr "ę¤åøåä¼¼ä¹å·²č¢«å é¤ć"
@@ -4023,7 +4155,7 @@ msgstr "ę¤å蔨为空ļ¼"
msgid "This name is already in use"
msgstr "评å称已被使ēØ"
-#: src/view/com/post-thread/PostThreadItem.tsx:123
+#: src/view/com/post-thread/PostThreadItem.tsx:125
msgid "This post has been deleted."
msgstr "ę¤åøå·²č¢«å é¤ć"
@@ -4047,7 +4179,11 @@ msgstr "ę¤ēØę·å
å«åØä½ å·²éčē <0/> å蔨äøć"
msgid "This warning is only available for posts with media attached."
msgstr "ę¤č¦åä»
éēØäŗéåø¦åŖä½ēåøåć"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:221
+#: src/components/dialogs/MutedWords.tsx:236
+msgid "This will delete {0} from your muted words. You can always add it back later."
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:237
msgid "This will hide this post from your feeds."
msgstr "čæå°åØä½ ēäæ”ęÆęµäøéčę¤åøåć"
@@ -4064,6 +4200,10 @@ msgstr "åå±ęØ”å¼"
msgid "Threads Preferences"
msgstr "讨论串é¦é锹"
+#: src/components/dialogs/MutedWords.tsx:95
+msgid "Toggle between muted word options."
+msgstr ""
+
#: src/view/com/util/forms/DropdownButton.tsx:246
msgid "Toggle dropdown"
msgstr "åę¢äøęčå"
@@ -4072,9 +4212,9 @@ msgstr "åę¢äøęčå"
msgid "Transformations"
msgstr "转ę¢"
-#: src/view/com/post-thread/PostThreadItem.tsx:679
-#: src/view/com/post-thread/PostThreadItem.tsx:681
-#: src/view/com/util/forms/PostDropdownBtn.tsx:154
+#: src/view/com/post-thread/PostThreadItem.tsx:685
+#: src/view/com/post-thread/PostThreadItem.tsx:687
+#: src/view/com/util/forms/PostDropdownBtn.tsx:156
msgid "Translate"
msgstr "ēæ»čÆ"
@@ -4139,15 +4279,24 @@ msgstr "å¾éę¾ļ¼ä½ äøē¬¦åå建蓦ę·ēč¦ę±ć"
msgid "Unlike"
msgstr "åę¶å欢"
+#: src/components/TagMenu/index.tsx:253
#: src/view/screens/ProfileList.tsx:597
msgid "Unmute"
msgstr "åę¶éč"
+#: src/components/TagMenu/index.web.tsx:90
+msgid "Unmute {truncatedTag}"
+msgstr ""
+
#: src/view/com/profile/ProfileHeader.tsx:326
msgid "Unmute Account"
msgstr "åę¶éč蓦ę·"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:200
+#: src/components/TagMenu/index.tsx:210
+msgid "Unmute all {tag} posts"
+msgstr ""
+
+#: src/view/com/util/forms/PostDropdownBtn.tsx:202
msgid "Unmute thread"
msgstr "åę¶éč讨论串"
@@ -4344,6 +4493,10 @@ msgstr "ę们åøęä½ åØę¤åŗ¦čæęåæ«ēę¶å
ć请记ä½ļ¼Bluesky ęÆļ¼"
msgid "We ran out of posts from your follows. Here's the latest from <0/>."
msgstr "ę们已ē»ēå®äŗä½ å
³ę³ØēåøåćčæęÆę„čŖ <0/> ēęę°ę¶ęÆć"
+#: src/components/dialogs/MutedWords.tsx:161
+msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown."
+msgstr ""
+
#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124
msgid "We recommend our \"Discover\" feed:"
msgstr "ę们ęØčę们ē \"Discover\" äæ”ęÆęµ:"
@@ -4372,7 +4525,11 @@ msgstr "ę们éåøøé«å
“ä½ å å
„ę们ļ¼"
msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}."
msgstr "å¾ę±ęļ¼ę们ę ę³č§£ęę¤å蔨ćå¦ęé®é¢ęē»åēļ¼čÆ·čē³»å蔨å建č
ļ¼@{handleOrDid}ć"
-#: src/view/screens/Search/Search.tsx:253
+#: src/components/dialogs/MutedWords.tsx:182
+msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
+msgstr ""
+
+#: src/view/screens/Search/Search.tsx:254
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "å¾ę±ęļ¼ę ę³å®ęä½ ēęē“¢ć请ēØååčÆć"
@@ -4393,7 +4550,7 @@ msgid "What is the issue with this {collectionName}?"
msgstr "čæäøŖ {collectionName} ęä»ä¹é®é¢ļ¼"
#: src/view/com/auth/SplashScreen.tsx:59
-#: src/view/com/composer/Composer.tsx:279
+#: src/view/com/composer/Composer.tsx:286
msgid "What's up?"
msgstr "åēäŗä»ä¹ę°é²äŗļ¼"
@@ -4414,11 +4571,11 @@ msgstr "č°åÆä»„åå¤"
msgid "Wide"
msgstr "宽"
-#: src/view/com/composer/Composer.tsx:415
+#: src/view/com/composer/Composer.tsx:422
msgid "Write post"
msgstr "ę°ååøå"
-#: src/view/com/composer/Composer.tsx:278
+#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Prompt.tsx:33
msgid "Write your reply"
msgstr "ę°åä½ ēåå¤"
@@ -4475,7 +4632,7 @@ msgstr "ä½ ē®åčæę²”ęä»»ä½äæåēäæ”ęÆęµļ¼"
msgid "You don't have any saved feeds."
msgstr "ä½ ē®åčæę²”ęä»»ä½äæåēäæ”ęÆęµć"
-#: src/view/com/post-thread/PostThread.tsx:464
+#: src/view/com/post-thread/PostThread.tsx:465
msgid "You have blocked the author or you have been blocked by the author."
msgstr "ä½ å·²å±č½čÆ„ä½č
ļ¼ęä½ å·²č¢«čÆ„ä½č
å±č½ć"
@@ -4515,6 +4672,10 @@ msgstr "ä½ å°ęŖåå»ŗä»»ä½ App äøēØåÆē ļ¼åÆä»„éčæē¹å»äøé¢ēę
msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account."
msgstr "ä½ čæę²”ęéčä»»ä½č“¦å·ćč¦éč蓦å·ļ¼čÆ·č½¬å°å
¶äøŖäŗŗčµęå¹¶åØå
¶č“¦å·äøēčåäøéę© \"éč蓦å·\"ć"
+#: src/components/dialogs/MutedWords.tsx:202
+msgid "You haven't muted any words or tags yet"
+msgstr ""
+
#: src/view/com/modals/ContentFilteringSettings.tsx:175
msgid "You must be 18 or older to enable adult content."
msgstr "ä½ åæ
锻幓滔18å²å仄äøęč½åÆēØęäŗŗå
容ć"
@@ -4523,11 +4684,11 @@ msgstr "ä½ åæ
锻幓滔18å²å仄äøęč½åÆēØęäŗŗå
容ć"
msgid "You must be 18 years or older to enable adult content"
msgstr "ä½ åæ
锻幓滔18å²å仄äøęč½åÆēØęäŗŗå
容"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:127
+#: src/view/com/util/forms/PostDropdownBtn.tsx:129
msgid "You will no longer receive notifications for this thread"
msgstr "ä½ å°äøåę¶å°čæę”讨论串ēéē„"
-#: src/view/com/util/forms/PostDropdownBtn.tsx:130
+#: src/view/com/util/forms/PostDropdownBtn.tsx:132
msgid "You will now receive notifications for this thread"
msgstr "ä½ å°ę¶å°čæę”讨论串ēéē„"
@@ -4613,11 +4774,15 @@ msgstr "ä½ ēå®ę“ēØę·čÆå«ē¬¦å°äæ®ę¹äøŗ <0>@{0}0>"
#~ msgid "Your invite codes are hidden when logged in using an App Password"
#~ msgstr "åØä½æēØ App äøēØåÆē ē»å½ę¶ļ¼ä½ ēé请ē å°č¢«éč"
+#: src/components/dialogs/MutedWords.tsx:173
+msgid "Your muted words"
+msgstr ""
+
#: src/view/com/modals/ChangePassword.tsx:155
msgid "Your password has been changed successfully!"
msgstr "ä½ ēåÆē å·²ę“ę¹ęåļ¼"
-#: src/view/com/composer/Composer.tsx:267
+#: src/view/com/composer/Composer.tsx:274
msgid "Your post has been published"
msgstr "ä½ ēåøåå·²åé"
@@ -4632,7 +4797,7 @@ msgstr "ä½ ēåøåćē¹čµåå±č½ęÆå
¬å¼åÆč§ēļ¼čéčäøåÆč§ć
msgid "Your profile"
msgstr "ä½ ēäøŖäŗŗčµę"
-#: src/view/com/composer/Composer.tsx:266
+#: src/view/com/composer/Composer.tsx:273
msgid "Your reply has been published"
msgstr "ä½ ēåå¤å·²åé"
diff --git a/src/platform/markBundleStartTime.web.ts b/src/platform/markBundleStartTime.web.ts
new file mode 100644
index 0000000000..cd64c9f1c3
--- /dev/null
+++ b/src/platform/markBundleStartTime.web.ts
@@ -0,0 +1,2 @@
+// @ts-ignore Web-only. On RN, this is set by Metro.
+window.__BUNDLE_START_TIME__ = performance.now()
diff --git a/src/routes.ts b/src/routes.ts
index 62732985ce..23ec880de2 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -34,4 +34,5 @@ export const router = new Router({
TermsOfService: '/support/tos',
CommunityGuidelines: '/support/community-guidelines',
CopyrightPolicy: '/support/copyright',
+ Hashtag: '/hashtag/:tag',
})
diff --git a/src/screens/Hashtag.tsx b/src/screens/Hashtag.tsx
new file mode 100644
index 0000000000..776cc585e3
--- /dev/null
+++ b/src/screens/Hashtag.tsx
@@ -0,0 +1,165 @@
+import React from 'react'
+import {ListRenderItemInfo, Pressable} from 'react-native'
+import {useFocusEffect} from '@react-navigation/native'
+import {useSetMinimalShellMode} from 'state/shell'
+import {ViewHeader} from 'view/com/util/ViewHeader'
+import {NativeStackScreenProps} from '@react-navigation/native-stack'
+import {CommonNavigatorParams} from 'lib/routes/types'
+import {useSearchPostsQuery} from 'state/queries/search-posts'
+import {Post} from 'view/com/post/Post'
+import {PostView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
+import {enforceLen} from 'lib/strings/helpers'
+import {
+ ListFooter,
+ ListHeaderDesktop,
+ ListMaybePlaceholder,
+} from '#/components/Lists'
+import {List} from 'view/com/util/List'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {sanitizeHandle} from 'lib/strings/handles'
+import {ArrowOutOfBox_Stroke2_Corner0_Rounded} from '#/components/icons/ArrowOutOfBox'
+import {shareUrl} from 'lib/sharing'
+import {HITSLOP_10} from 'lib/constants'
+import {isNative} from 'platform/detection'
+import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
+
+const renderItem = ({item}: ListRenderItemInfo) => {
+ return
+}
+
+const keyExtractor = (item: PostView, index: number) => {
+ return `${item.uri}-${index}`
+}
+
+export default function HashtagScreen({
+ route,
+}: NativeStackScreenProps) {
+ const {tag, author} = route.params
+ const setMinimalShellMode = useSetMinimalShellMode()
+ const {_} = useLingui()
+ const initialNumToRender = useInitialNumToRender()
+ const [isPTR, setIsPTR] = React.useState(false)
+
+ const fullTag = React.useMemo(() => {
+ return `#${decodeURIComponent(tag)}`
+ }, [tag])
+
+ const queryParam = React.useMemo(() => {
+ if (!author) return fullTag
+ return `${fullTag} from:${sanitizeHandle(author)}`
+ }, [fullTag, author])
+
+ const headerTitle = React.useMemo(() => {
+ return enforceLen(fullTag.toLowerCase(), 24, true, 'middle')
+ }, [fullTag])
+
+ const sanitizedAuthor = React.useMemo(() => {
+ if (!author) return
+ return sanitizeHandle(author)
+ }, [author])
+
+ const {
+ data,
+ isFetching,
+ isLoading,
+ isRefetching,
+ isError,
+ error,
+ refetch,
+ fetchNextPage,
+ hasNextPage,
+ } = useSearchPostsQuery({query: queryParam})
+
+ const posts = React.useMemo(() => {
+ return data?.pages.flatMap(page => page.posts) || []
+ }, [data])
+
+ useFocusEffect(
+ React.useCallback(() => {
+ setMinimalShellMode(false)
+ }, [setMinimalShellMode]),
+ )
+
+ const onShare = React.useCallback(() => {
+ const url = new URL('https://bsky.app')
+ url.pathname = `/hashtag/${decodeURIComponent(tag)}`
+ if (author) {
+ url.searchParams.set('author', author)
+ }
+ shareUrl(url.toString())
+ }, [tag, author])
+
+ const onRefresh = React.useCallback(async () => {
+ setIsPTR(true)
+ await refetch()
+ setIsPTR(false)
+ }, [refetch])
+
+ const onEndReached = React.useCallback(() => {
+ if (isFetching || !hasNextPage || error) return
+ fetchNextPage()
+ }, [isFetching, hasNextPage, error, fetchNextPage])
+
+ return (
+ <>
+ (
+
+
+
+ )
+ : undefined
+ }
+ />
+
+ {!isLoading && posts.length > 0 && (
+
+ data={posts}
+ renderItem={renderItem}
+ keyExtractor={keyExtractor}
+ refreshing={isPTR}
+ onRefresh={onRefresh}
+ onEndReached={onEndReached}
+ onEndReachedThreshold={4}
+ // @ts-ignore web only -prf
+ desktopFixedHeight
+ ListHeaderComponent={
+
+ }
+ ListFooterComponent={
+
+ }
+ initialNumToRender={initialNumToRender}
+ windowSize={11}
+ />
+ )}
+ >
+ )
+}
diff --git a/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx b/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx
index d5e730ffaf..0bff534362 100644
--- a/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx
+++ b/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx
@@ -119,7 +119,7 @@ export function AdultContentEnabledPref({
- OK
+ prompt.close()}>OK
>
diff --git a/src/screens/Onboarding/state.ts b/src/screens/Onboarding/state.ts
index bd8205ca2d..969edbdd24 100644
--- a/src/screens/Onboarding/state.ts
+++ b/src/screens/Onboarding/state.ts
@@ -232,7 +232,7 @@ export function reducer(
})
if (s.activeStep !== state.activeStep) {
- logger.info(`onboarding: step changed`, {activeStep: state.activeStep})
+ logger.debug(`onboarding: step changed`, {activeStep: state.activeStep})
}
return state
diff --git a/src/state/dialogs/index.tsx b/src/state/dialogs/index.tsx
index ae762bd97e..90aaca4f8b 100644
--- a/src/state/dialogs/index.tsx
+++ b/src/state/dialogs/index.tsx
@@ -1,21 +1,32 @@
import React from 'react'
-import {DialogControlProps} from '#/components/Dialog'
+import {DialogControlRefProps} from '#/components/Dialog'
import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
const DialogContext = React.createContext<{
+ /**
+ * The currently active `useDialogControl` hooks.
+ */
activeDialogs: React.MutableRefObject<
- Map>
+ Map>
>
+ /**
+ * The currently open dialogs, referenced by their IDs, generated from
+ * `useId`.
+ */
+ openDialogs: string[]
}>({
activeDialogs: {
current: new Map(),
},
+ openDialogs: [],
})
const DialogControlContext = React.createContext<{
- closeAllDialogs(): void
+ closeAllDialogs(): boolean
+ setDialogIsOpen(id: string, isOpen: boolean): void
}>({
- closeAllDialogs: () => {},
+ closeAllDialogs: () => false,
+ setDialogIsOpen: () => {},
})
export function useDialogStateContext() {
@@ -28,13 +39,34 @@ export function useDialogStateControlContext() {
export function Provider({children}: React.PropsWithChildren<{}>) {
const activeDialogs = React.useRef<
- Map>
+ Map>
>(new Map())
+ const [openDialogs, setOpenDialogs] = React.useState([])
+
const closeAllDialogs = React.useCallback(() => {
activeDialogs.current.forEach(dialog => dialog.current.close())
- }, [])
- const context = React.useMemo(() => ({activeDialogs}), [])
- const controls = React.useMemo(() => ({closeAllDialogs}), [closeAllDialogs])
+ return openDialogs.length > 0
+ }, [openDialogs])
+
+ const setDialogIsOpen = React.useCallback(
+ (id: string, isOpen: boolean) => {
+ setOpenDialogs(prev => {
+ const filtered = prev.filter(dialogId => dialogId !== id) as string[]
+ return isOpen ? [...filtered, id] : filtered
+ })
+ },
+ [setOpenDialogs],
+ )
+
+ const context = React.useMemo(
+ () => ({activeDialogs, openDialogs}),
+ [openDialogs],
+ )
+ const controls = React.useMemo(
+ () => ({closeAllDialogs, setDialogIsOpen}),
+ [closeAllDialogs, setDialogIsOpen],
+ )
+
return (
diff --git a/src/state/models/media/gallery.ts b/src/state/models/media/gallery.ts
index 04023bf820..9c8c13010d 100644
--- a/src/state/models/media/gallery.ts
+++ b/src/state/models/media/gallery.ts
@@ -4,11 +4,21 @@ import {Image as RNImage} from 'react-native-image-crop-picker'
import {openPicker} from 'lib/media/picker'
import {getImageDim} from 'lib/media/manip'
+interface InitialImageUri {
+ uri: string
+ width: number
+ height: number
+}
+
export class GalleryModel {
images: ImageModel[] = []
- constructor() {
+ constructor(uris?: {uri: string; width: number; height: number}[]) {
makeAutoObservable(this)
+
+ if (uris) {
+ this.addFromUris(uris)
+ }
}
get isEmpty() {
@@ -23,7 +33,7 @@ export class GalleryModel {
return this.images.some(image => image.altText.trim() === '')
}
- async add(image_: Omit) {
+ *add(image_: Omit) {
if (this.size >= 4) {
return
}
@@ -86,4 +96,15 @@ export class GalleryModel {
}),
)
}
+
+ async addFromUris(uris: InitialImageUri[]) {
+ for (const uriObj of uris) {
+ this.add({
+ mime: 'image/jpeg',
+ height: uriObj.height,
+ width: uriObj.width,
+ path: uriObj.uri,
+ })
+ }
+ }
}
diff --git a/src/state/persisted/__tests__/migrate.test.ts b/src/state/persisted/__tests__/migrate.test.ts
index e4b55d5da6..97767e2732 100644
--- a/src/state/persisted/__tests__/migrate.test.ts
+++ b/src/state/persisted/__tests__/migrate.test.ts
@@ -26,7 +26,7 @@ test('migrate: fresh install', async () => {
expect(AsyncStorage.getItem).toHaveBeenCalledWith('root')
expect(read).toHaveBeenCalledTimes(1)
- expect(logger.info).toHaveBeenCalledWith(
+ expect(logger.debug).toHaveBeenCalledWith(
'persisted state: no migration needed',
)
})
@@ -38,7 +38,7 @@ test('migrate: fresh install, existing new storage', async () => {
expect(AsyncStorage.getItem).toHaveBeenCalledWith('root')
expect(read).toHaveBeenCalledTimes(1)
- expect(logger.info).toHaveBeenCalledWith(
+ expect(logger.debug).toHaveBeenCalledWith(
'persisted state: no migration needed',
)
})
@@ -68,7 +68,7 @@ test('migrate: has legacy data', async () => {
await migrate()
expect(write).toHaveBeenCalledWith(transform(fixtures.LEGACY_DATA_DUMP))
- expect(logger.info).toHaveBeenCalledWith(
+ expect(logger.debug).toHaveBeenCalledWith(
'persisted state: migrated legacy storage',
)
})
diff --git a/src/state/persisted/index.ts b/src/state/persisted/index.ts
index 2f34c2dbff..f57172d2fe 100644
--- a/src/state/persisted/index.ts
+++ b/src/state/persisted/index.ts
@@ -19,7 +19,7 @@ const _emitter = new EventEmitter()
* the Provider.
*/
export async function init() {
- logger.info('persisted state: initializing')
+ logger.debug('persisted state: initializing')
broadcast.onmessage = onBroadcastMessage
@@ -27,11 +27,11 @@ export async function init() {
await migrate() // migrate old store
const stored = await store.read() // check for new store
if (!stored) {
- logger.info('persisted state: initializing default storage')
+ logger.debug('persisted state: initializing default storage')
await store.write(defaults) // opt: init new store
}
_state = stored || defaults // return new store
- logger.log('persisted state: initialized')
+ logger.debug('persisted state: initialized')
} catch (e) {
logger.error('persisted state: failed to load root state from storage', {
message: e,
diff --git a/src/state/persisted/legacy.ts b/src/state/persisted/legacy.ts
index cce080c84c..fd94a96a24 100644
--- a/src/state/persisted/legacy.ts
+++ b/src/state/persisted/legacy.ts
@@ -121,7 +121,7 @@ export function transform(legacy: Partial): Schema {
* local storage AND old storage exists.
*/
export async function migrate() {
- logger.info('persisted state: check need to migrate')
+ logger.debug('persisted state: check need to migrate')
try {
const rawLegacyData = await AsyncStorage.getItem(
@@ -131,7 +131,7 @@ export async function migrate() {
const alreadyMigrated = Boolean(newData)
if (!alreadyMigrated && rawLegacyData) {
- logger.info('persisted state: migrating legacy storage')
+ logger.debug('persisted state: migrating legacy storage')
const legacyData = JSON.parse(rawLegacyData)
const newData = transform(legacyData)
@@ -139,14 +139,14 @@ export async function migrate() {
if (validate.success) {
await write(newData)
- logger.info('persisted state: migrated legacy storage')
+ logger.debug('persisted state: migrated legacy storage')
} else {
logger.error('persisted state: legacy data failed validation', {
message: validate.error,
})
}
} else {
- logger.info('persisted state: no migration needed')
+ logger.debug('persisted state: no migration needed')
}
} catch (e: any) {
logger.error(e, {
diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts
index 67294ece27..1fa92c291f 100644
--- a/src/state/queries/feed.ts
+++ b/src/state/queries/feed.ts
@@ -1,11 +1,9 @@
-import React from 'react'
import {
useQuery,
useInfiniteQuery,
InfiniteData,
QueryKey,
useMutation,
- useQueryClient,
} from '@tanstack/react-query'
import {
AtUri,
@@ -15,7 +13,6 @@ import {
AppBskyUnspeccedGetPopularFeedGenerators,
} from '@atproto/api'
-import {logger} from '#/logger'
import {router} from '#/routes'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
@@ -219,83 +216,59 @@ const FOLLOWING_FEED_STUB: FeedSourceInfo = {
likeUri: '',
}
-export function usePinnedFeedsInfos(): {
- feeds: FeedSourceInfo[]
- hasPinnedCustom: boolean
- isLoading: boolean
-} {
- const queryClient = useQueryClient()
- const [tabs, setTabs] = React.useState([
- FOLLOWING_FEED_STUB,
- ])
- const [isLoading, setLoading] = React.useState(true)
- const {data: preferences} = usePreferencesQuery()
+export function usePinnedFeedsInfos() {
+ const {data: preferences, isLoading: isLoadingPrefs} = usePreferencesQuery()
+ const pinnedUris = preferences?.feeds?.pinned ?? []
- const hasPinnedCustom = React.useMemo(() => {
- return tabs.some(tab => tab !== FOLLOWING_FEED_STUB)
- }, [tabs])
+ return useQuery({
+ staleTime: STALE.INFINITY,
+ enabled: !isLoadingPrefs,
+ queryKey: ['pinnedFeedsInfos', pinnedUris.join(',')],
+ queryFn: async () => {
+ let resolved = new Map()
- React.useEffect(() => {
- if (!preferences?.feeds?.pinned) return
- const uris = preferences.feeds.pinned
-
- async function fetchFeedInfo() {
- const reqs = []
-
- for (const uri of uris) {
- const cached = queryClient.getQueryData(
- feedSourceInfoQueryKey({uri}),
- )
-
- if (cached) {
- reqs.push(cached)
- } else {
- reqs.push(
- (async () => {
- // these requests can fail, need to filter those out
- try {
- return await queryClient.fetchQuery({
- staleTime: STALE.SECONDS.FIFTEEN,
- queryKey: feedSourceInfoQueryKey({uri}),
- queryFn: async () => {
- const type = getFeedTypeFromUri(uri)
-
- if (type === 'feed') {
- const res =
- await getAgent().app.bsky.feed.getFeedGenerator({
- feed: uri,
- })
- return hydrateFeedGenerator(res.data.view)
- } else {
- const res = await getAgent().app.bsky.graph.getList({
- list: uri,
- limit: 1,
- })
- return hydrateList(res.data.list)
- }
- },
- })
- } catch (e) {
- // expected failure
- logger.info(`usePinnedFeedsInfos: failed to fetch ${uri}`, {
- error: e,
- })
- }
- })(),
- )
- }
+ // Get all feeds. We can do this in a batch.
+ const feedUris = pinnedUris.filter(
+ uri => getFeedTypeFromUri(uri) === 'feed',
+ )
+ let feedsPromise = Promise.resolve()
+ if (feedUris.length > 0) {
+ feedsPromise = getAgent()
+ .app.bsky.feed.getFeedGenerators({
+ feeds: feedUris,
+ })
+ .then(res => {
+ for (let feedView of res.data.feeds) {
+ resolved.set(feedView.uri, hydrateFeedGenerator(feedView))
+ }
+ })
}
- const views = (await Promise.all(reqs)).filter(
- Boolean,
- ) as FeedSourceInfo[]
+ // Get all lists. This currently has to be done individually.
+ const listUris = pinnedUris.filter(
+ uri => getFeedTypeFromUri(uri) === 'list',
+ )
+ const listsPromises = listUris.map(listUri =>
+ getAgent()
+ .app.bsky.graph.getList({
+ list: listUri,
+ limit: 1,
+ })
+ .then(res => {
+ const listView = res.data.list
+ resolved.set(listView.uri, hydrateList(listView))
+ }),
+ )
- setTabs([FOLLOWING_FEED_STUB].concat(views))
- setLoading(false)
- }
-
- fetchFeedInfo()
- }, [queryClient, setTabs, preferences?.feeds?.pinned])
-
- return {feeds: tabs, hasPinnedCustom, isLoading}
+ // The returned result will have the original order.
+ const result = [FOLLOWING_FEED_STUB]
+ await Promise.allSettled([feedsPromise, ...listsPromises])
+ for (let pinnedUri of pinnedUris) {
+ if (resolved.has(pinnedUri)) {
+ result.push(resolved.get(pinnedUri))
+ }
+ }
+ return result
+ },
+ })
}
diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts
index 4899e53ff7..0e6eef52ca 100644
--- a/src/state/queries/post-feed.ts
+++ b/src/state/queries/post-feed.ts
@@ -4,6 +4,7 @@ import {
AppBskyFeedDefs,
AppBskyFeedPost,
ModerationDecision,
+ AtUri,
} from '@atproto/api'
import {
useInfiniteQuery,
@@ -32,6 +33,7 @@ import {KnownError} from '#/view/com/posts/FeedErrorMessage'
import {embedViewRecordToPostView, getEmbeddedPost} from './util'
import {useModerationOpts} from './preferences'
import {queryClient} from 'lib/react-query'
+import {BSKY_FEED_OWNER_DIDS} from 'lib/constants'
type ActorDid = string
type AuthorFilter =
@@ -140,24 +142,41 @@ export function usePostFeedQuery(
cursor: undefined,
}
- const res = await api.fetch({cursor, limit: PAGE_SIZE})
- precacheFeedPostProfiles(queryClient, res.feed)
+ try {
+ const res = await api.fetch({cursor, limit: PAGE_SIZE})
+ precacheFeedPostProfiles(queryClient, res.feed)
- /*
- * If this is a public view, we need to check if posts fail moderation.
- * If all fail, we throw an error. If only some fail, we continue and let
- * moderations happen later, which results in some posts being shown and
- * some not.
- */
- if (!getAgent().session) {
- assertSomePostsPassModeration(res.feed)
- }
+ /*
+ * If this is a public view, we need to check if posts fail moderation.
+ * If all fail, we throw an error. If only some fail, we continue and let
+ * moderations happen later, which results in some posts being shown and
+ * some not.
+ */
+ if (!getAgent().session) {
+ assertSomePostsPassModeration(res.feed)
+ }
- return {
- api,
- cursor: res.cursor,
- feed: res.feed,
- fetchedAt: Date.now(),
+ return {
+ api,
+ cursor: res.cursor,
+ feed: res.feed,
+ fetchedAt: Date.now(),
+ }
+ } catch (e) {
+ const feedDescParts = feedDesc.split('|')
+ const feedOwnerDid = new AtUri(feedDescParts[1]).hostname
+
+ if (
+ feedDescParts[0] === 'feedgen' &&
+ BSKY_FEED_OWNER_DIDS.includes(feedOwnerDid)
+ ) {
+ logger.error(`Bluesky feed may be offline: ${feedOwnerDid}`, {
+ feedDesc,
+ jsError: e,
+ })
+ }
+
+ throw e
}
},
initialPageParam: undefined,
@@ -264,7 +283,7 @@ export function usePostFeedQuery(
.success
) {
return {
- _reactKey: `${slice._reactKey}-${i}`,
+ _reactKey: `${slice._reactKey}-${i}-${item.post.uri}`,
uri: item.post.uri,
post: item.post,
record: item.post.record,
diff --git a/src/state/queries/preferences/const.ts b/src/state/queries/preferences/const.ts
index a5d3035d5c..bc08da9870 100644
--- a/src/state/queries/preferences/const.ts
+++ b/src/state/queries/preferences/const.ts
@@ -7,7 +7,7 @@ import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/
export const DEFAULT_HOME_FEED_PREFS: UsePreferencesQueryResponse['feedViewPrefs'] =
{
hideReplies: false,
- hideRepliesByUnfollowed: false,
+ hideRepliesByUnfollowed: true,
hideRepliesByLikeCount: 0,
hideReposts: false,
hideQuotePosts: false,
diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts
index 0fa8f4dfbe..07d953c94c 100644
--- a/src/state/queries/preferences/index.ts
+++ b/src/state/queries/preferences/index.ts
@@ -4,6 +4,7 @@ import {
LabelPreference,
BskyFeedViewPreference,
ModerationOpts,
+ AppBskyActorDefs,
} from '@atproto/api'
import {track} from '#/lib/analytics/analytics'
@@ -92,6 +93,7 @@ export function useModerationOpts() {
...moderationPrefs,
hiddenPosts,
},
+ mutedWords: prefs.data.mutedWords || [], // TODO
labelDefs,
}
}, [override, currentAccount, labelDefs, prefs.data, hiddenPosts])
@@ -171,7 +173,7 @@ export function usePreferencesSetBirthDateMutation() {
return useMutation({
mutationFn: async ({birthDate}: {birthDate: Date}) => {
- await getAgent().setPersonalDetails({birthDate})
+ await getAgent().setPersonalDetails({birthDate: birthDate.toISOString()})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: preferencesQueryKey,
@@ -285,3 +287,45 @@ export function useUnpinFeedMutation() {
},
})
}
+
+export function useUpsertMutedWordsMutation() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: async (mutedWords: AppBskyActorDefs.MutedWord[]) => {
+ await getAgent().upsertMutedWords(mutedWords)
+ // triggers a refetch
+ await queryClient.invalidateQueries({
+ queryKey: preferencesQueryKey,
+ })
+ },
+ })
+}
+
+export function useUpdateMutedWordMutation() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
+ await getAgent().updateMutedWord(mutedWord)
+ // triggers a refetch
+ await queryClient.invalidateQueries({
+ queryKey: preferencesQueryKey,
+ })
+ },
+ })
+}
+
+export function useRemoveMutedWordMutation() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: async (mutedWord: AppBskyActorDefs.MutedWord) => {
+ await getAgent().removeMutedWord(mutedWord)
+ // triggers a refetch
+ await queryClient.invalidateQueries({
+ queryKey: preferencesQueryKey,
+ })
+ },
+ })
+}
diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx
index 772daf1395..f3b3d70ae7 100644
--- a/src/state/session/index.tsx
+++ b/src/state/session/index.tsx
@@ -135,7 +135,7 @@ function createPersistSessionHandler(
accessJwt: session?.accessJwt,
}
- logger.info(`session: persistSession`, {
+ logger.debug(`session: persistSession`, {
event,
deactivated: refreshedAccount.deactivated,
})
@@ -324,7 +324,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
)
const logout = React.useCallback(async () => {
- logger.info(`session: logout`)
+ logger.debug(`session: logout`)
clearCurrentAccount()
setStateAndPersist(s => {
return {
@@ -380,7 +380,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}
if (canReusePrevSession) {
- logger.info(`session: attempting to reuse previous session`)
+ logger.debug(`session: attempting to reuse previous session`)
agent.session = prevSession
__globalAgent = agent
@@ -390,7 +390,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
if (prevSession.deactivated) {
// don't attempt to resume
// use will be taken to the deactivated screen
- logger.info(`session: reusing session for deactivated account`)
+ logger.debug(`session: reusing session for deactivated account`)
return
}
@@ -416,7 +416,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
__globalAgent = PUBLIC_BSKY_AGENT
})
} else {
- logger.info(`session: attempting to resume using previous session`)
+ logger.debug(`session: attempting to resume using previous session`)
try {
const freshAccount = await resumeSessionWithFreshAccount()
@@ -437,7 +437,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}
async function resumeSessionWithFreshAccount(): Promise {
- logger.info(`session: resumeSessionWithFreshAccount`)
+ logger.debug(`session: resumeSessionWithFreshAccount`)
await networkRetry(1, () => agent.resumeSession(prevSession))
@@ -558,11 +558,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
return persisted.onUpdate(() => {
const session = persisted.get('session')
- logger.info(`session: persisted onUpdate`, {})
+ logger.debug(`session: persisted onUpdate`, {})
if (session.currentAccount && session.currentAccount.refreshJwt) {
if (session.currentAccount?.did !== state.currentAccount?.did) {
- logger.info(`session: persisted onUpdate, switching accounts`, {
+ logger.debug(`session: persisted onUpdate, switching accounts`, {
from: {
did: state.currentAccount?.did,
handle: state.currentAccount?.handle,
@@ -575,7 +575,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
initSession(session.currentAccount)
} else {
- logger.info(`session: persisted onUpdate, updating session`, {})
+ logger.debug(`session: persisted onUpdate, updating session`, {})
/*
* Use updated session in this tab's agent. Do not call
diff --git a/src/state/shell/composer.tsx b/src/state/shell/composer.tsx
index c8392b825f..a09e8fba9f 100644
--- a/src/state/shell/composer.tsx
+++ b/src/state/shell/composer.tsx
@@ -38,6 +38,8 @@ export interface ComposerOpts {
quote?: ComposerOptsQuote
mention?: string // handle of user to mention
openPicker?: (pos: DOMRect | undefined) => void
+ text?: string
+ imageUris?: {uri: string; width: number; height: number}[]
}
type StateContext = ComposerOpts | undefined
diff --git a/src/state/util.ts b/src/state/util.ts
index 57f4331b05..f65d14a84c 100644
--- a/src/state/util.ts
+++ b/src/state/util.ts
@@ -3,6 +3,7 @@ import {useLightboxControls} from './lightbox'
import {useModalControls} from './modals'
import {useComposerControls} from './shell/composer'
import {useSetDrawerOpen} from './shell/drawer-open'
+import {useDialogStateControlContext} from '#/state/dialogs'
/**
* returns true if something was closed
@@ -12,6 +13,7 @@ export function useCloseAnyActiveElement() {
const {closeLightbox} = useLightboxControls()
const {closeModal} = useModalControls()
const {closeComposer} = useComposerControls()
+ const {closeAllDialogs} = useDialogStateControlContext()
const setDrawerOpen = useSetDrawerOpen()
return useCallback(() => {
if (closeLightbox()) {
@@ -23,9 +25,12 @@ export function useCloseAnyActiveElement() {
if (closeComposer()) {
return true
}
+ if (closeAllDialogs()) {
+ return true
+ }
setDrawerOpen(false)
return false
- }, [closeLightbox, closeModal, closeComposer, setDrawerOpen])
+ }, [closeLightbox, closeModal, closeComposer, setDrawerOpen, closeAllDialogs])
}
/**
@@ -35,11 +40,19 @@ export function useCloseAllActiveElements() {
const {closeLightbox} = useLightboxControls()
const {closeAllModals} = useModalControls()
const {closeComposer} = useComposerControls()
+ const {closeAllDialogs: closeAlfDialogs} = useDialogStateControlContext()
const setDrawerOpen = useSetDrawerOpen()
return useCallback(() => {
closeLightbox()
closeAllModals()
closeComposer()
+ closeAlfDialogs()
setDrawerOpen(false)
- }, [closeLightbox, closeAllModals, closeComposer, setDrawerOpen])
+ }, [
+ closeLightbox,
+ closeAllModals,
+ closeComposer,
+ closeAlfDialogs,
+ setDrawerOpen,
+ ])
}
diff --git a/src/view/com/auth/create/Step1.tsx b/src/view/com/auth/create/Step1.tsx
index 4c70184850..c1bec535f5 100644
--- a/src/view/com/auth/create/Step1.tsx
+++ b/src/view/com/auth/create/Step1.tsx
@@ -4,7 +4,6 @@ import {
Keyboard,
StyleSheet,
TouchableOpacity,
- TouchableWithoutFeedback,
View,
} from 'react-native'
import {CreateAccountState, CreateAccountDispatch, is18} from './state'
@@ -19,7 +18,6 @@ import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
import {isWeb} from 'platform/detection'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
-import {useModalControls} from '#/state/modals'
import {logger} from '#/logger'
import {
FontAwesomeIcon,
@@ -49,7 +47,6 @@ export function Step1({
}) {
const pal = usePalette('default')
const {_} = useLingui()
- const {openModal} = useModalControls()
const serverInputControl = useDialogControl()
const onPressSelectService = React.useCallback(() => {
@@ -57,10 +54,6 @@ export function Step1({
Keyboard.dismiss()
}, [serverInputControl])
- const onPressWaitlist = React.useCallback(() => {
- openModal({name: 'waitlist'})
- }, [openModal])
-
const birthDate = React.useMemo(() => {
return sanitizeDate(uiState.birthDate)
}, [uiState.birthDate])
@@ -164,23 +157,7 @@ export function Step1({
)}
- {!uiState.inviteCode && uiState.isInviteCodeRequired ? (
-
-
- Don't have an invite code?{' '}
-
-
-
-
- Join the waitlist.
-
-
-
-
- ) : (
+ {uiState.inviteCode ? (
<>
)}
>
- )}
+ ) : undefined}
>
)}
diff --git a/src/view/com/auth/create/Step2.tsx b/src/view/com/auth/create/Step2.tsx
index a389203098..5c262977f1 100644
--- a/src/view/com/auth/create/Step2.tsx
+++ b/src/view/com/auth/create/Step2.tsx
@@ -133,8 +133,8 @@ function IsValidIcon({valid}: {valid: boolean}) {
const t = useTheme()
if (!valid) {
- return
+ return
}
- return
+ return
}
diff --git a/src/view/com/auth/login/LoginForm.tsx b/src/view/com/auth/login/LoginForm.tsx
index e480de7a4c..fdba9f203f 100644
--- a/src/view/com/auth/login/LoginForm.tsx
+++ b/src/view/com/auth/login/LoginForm.tsx
@@ -107,7 +107,7 @@ export const LoginForm = ({
const errMsg = e.toString()
setIsProcessing(false)
if (errMsg.includes('Authentication Required')) {
- logger.info('Failed to login due to invalid credentials', {
+ logger.debug('Failed to login due to invalid credentials', {
error: errMsg,
})
setError(_(msg`Invalid username or password`))
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index f52b0890cc..399d420a68 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -71,6 +71,8 @@ export const ComposePost = observer(function ComposePost({
quote: initQuote,
mention: initMention,
openPicker,
+ text: initText,
+ imageUris: initImageUris,
}: Props) {
const {currentAccount} = useSession()
const {data: currentProfile} = useProfileQuery({did: currentAccount!.did})
@@ -91,7 +93,9 @@ export const ComposePost = observer(function ComposePost({
const [error, setError] = useState('')
const [richtext, setRichText] = useState(
new RichText({
- text: initMention
+ text: initText
+ ? initText
+ : initMention
? insertMentionAt(
`@${initMention}`,
initMention.length + 1,
@@ -110,7 +114,10 @@ export const ComposePost = observer(function ComposePost({
const [labels, setLabels] = useState([])
const [threadgate, setThreadgate] = useState([])
const [suggestedLinks, setSuggestedLinks] = useState>(new Set())
- const gallery = useMemo(() => new GalleryModel(), [])
+ const gallery = useMemo(
+ () => new GalleryModel(initImageUris),
+ [initImageUris],
+ )
const onClose = useCallback(() => {
closeComposer()
}, [closeComposer])
diff --git a/src/view/com/composer/text-input/TextInput.tsx b/src/view/com/composer/text-input/TextInput.tsx
index 17f9513b72..20be585c25 100644
--- a/src/view/com/composer/text-input/TextInput.tsx
+++ b/src/view/com/composer/text-input/TextInput.tsx
@@ -190,12 +190,11 @@ export const TextInput = forwardRef(function TextInputImpl(
let i = 0
return Array.from(richtext.segments()).map(segment => {
- const isTag = AppBskyRichtextFacet.isTag(segment.facet?.features?.[0])
return (
{segment.text}
diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx
index 199f1f7499..c62d11201f 100644
--- a/src/view/com/composer/text-input/TextInput.web.tsx
+++ b/src/view/com/composer/text-input/TextInput.web.tsx
@@ -23,6 +23,7 @@ import {Portal} from '#/components/Portal'
import {Text} from '../../util/text/Text'
import {Trans} from '@lingui/macro'
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
+import {TagDecorator} from './web/TagDecorator'
export interface TextInputRef {
focus: () => void
@@ -67,6 +68,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
() => [
Document,
LinkDecorator,
+ TagDecorator,
Mention.configure({
HTMLAttributes: {
class: 'mention',
diff --git a/src/view/com/composer/text-input/web/LinkDecorator.ts b/src/view/com/composer/text-input/web/LinkDecorator.ts
index 19945de086..e36ac80e42 100644
--- a/src/view/com/composer/text-input/web/LinkDecorator.ts
+++ b/src/view/com/composer/text-input/web/LinkDecorator.ts
@@ -18,6 +18,8 @@ import {Mark} from '@tiptap/core'
import {Plugin, PluginKey} from '@tiptap/pm/state'
import {Node as ProsemirrorNode} from '@tiptap/pm/model'
import {Decoration, DecorationSet} from '@tiptap/pm/view'
+import {URL_REGEX} from '@atproto/api'
+
import {isValidDomain} from 'lib/strings/url-helpers'
export const LinkDecorator = Mark.create({
@@ -78,8 +80,7 @@ function linkDecorator() {
function iterateUris(str: string, cb: (from: number, to: number) => void) {
let match
- const re =
- /(^|\s|\()((https?:\/\/[\S]+)|((?[a-z][a-z0-9]*(\.[a-z0-9]+)+)[\S]*))/gim
+ const re = URL_REGEX
while ((match = re.exec(str))) {
let uri = match[2]
if (!uri.startsWith('http')) {
diff --git a/src/view/com/composer/text-input/web/TagDecorator.ts b/src/view/com/composer/text-input/web/TagDecorator.ts
new file mode 100644
index 0000000000..2bf3184a8c
--- /dev/null
+++ b/src/view/com/composer/text-input/web/TagDecorator.ts
@@ -0,0 +1,91 @@
+/**
+ * TipTap is a stateful rich-text editor, which is extremely useful
+ * when you _want_ it to be stateful formatting such as bold and italics.
+ *
+ * However we also use "stateless" behaviors, specifically for URLs
+ * where the text itself drives the formatting.
+ *
+ * This plugin uses a regex to detect URIs and then applies
+ * link decorations (a with the "autolink") class. That avoids
+ * adding any stateful formatting to TipTap's document model.
+ *
+ * We then run the URI detection again when constructing the
+ * RichText object from TipTap's output and merge their features into
+ * the facet-set.
+ */
+
+import {Mark} from '@tiptap/core'
+import {Plugin, PluginKey} from '@tiptap/pm/state'
+import {Node as ProsemirrorNode} from '@tiptap/pm/model'
+import {Decoration, DecorationSet} from '@tiptap/pm/view'
+import {TAG_REGEX, TRAILING_PUNCTUATION_REGEX} from '@atproto/api'
+
+function getDecorations(doc: ProsemirrorNode) {
+ const decorations: Decoration[] = []
+
+ doc.descendants((node, pos) => {
+ if (node.isText && node.text) {
+ const regex = TAG_REGEX
+ const textContent = node.textContent
+
+ let match
+ while ((match = regex.exec(textContent))) {
+ const [matchedString, _, tag] = match
+
+ if (!tag || tag.replace(TRAILING_PUNCTUATION_REGEX, '').length > 64)
+ continue
+
+ const [trailingPunc = ''] = tag.match(TRAILING_PUNCTUATION_REGEX) || []
+ const matchedFrom = match.index + matchedString.indexOf(tag)
+ const matchedTo = matchedFrom + (tag.length - trailingPunc.length)
+
+ /*
+ * The match is exclusive of `#` so we need to adjust the start of the
+ * highlight by -1 to include the `#`
+ */
+ const start = pos + matchedFrom - 1
+ const end = pos + matchedTo
+
+ decorations.push(
+ Decoration.inline(start, end, {
+ class: 'autolink',
+ }),
+ )
+ }
+ }
+ })
+
+ return DecorationSet.create(doc, decorations)
+}
+
+const tagDecoratorPlugin: Plugin = new Plugin({
+ key: new PluginKey('link-decorator'),
+
+ state: {
+ init: (_, {doc}) => getDecorations(doc),
+ apply: (transaction, decorationSet) => {
+ if (transaction.docChanged) {
+ return getDecorations(transaction.doc)
+ }
+ return decorationSet.map(transaction.mapping, transaction.doc)
+ },
+ },
+
+ props: {
+ decorations(state) {
+ return tagDecoratorPlugin.getState(state)
+ },
+ },
+})
+
+export const TagDecorator = Mark.create({
+ name: 'tag-decorator',
+ priority: 1000,
+ keepOnSplit: false,
+ inclusive() {
+ return true
+ },
+ addProseMirrorPlugins() {
+ return [tagDecoratorPlugin]
+ },
+})
diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx
index 60814e8372..e6b5d1fb68 100644
--- a/src/view/com/feeds/FeedPage.tsx
+++ b/src/view/com/feeds/FeedPage.tsx
@@ -1,30 +1,24 @@
import React from 'react'
-import {
- FontAwesomeIcon,
- FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
import {useNavigation} from '@react-navigation/native'
import {useAnalytics} from 'lib/analytics/analytics'
import {useQueryClient} from '@tanstack/react-query'
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
import {MainScrollProvider} from '../util/MainScrollProvider'
-import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useSetMinimalShellMode} from '#/state/shell'
import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
import {ComposeIcon2} from 'lib/icons'
-import {colors, s} from 'lib/styles'
+import {s} from 'lib/styles'
import {View, useWindowDimensions} from 'react-native'
import {ListMethods} from '../util/List'
import {Feed} from '../posts/Feed'
-import {TextLink} from '../util/Link'
import {FAB} from '../util/fab/FAB'
import {LoadLatestBtn} from '../util/load-latest/LoadLatestBtn'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useSession} from '#/state/session'
import {useComposerControls} from '#/state/shell/composer'
-import {listenSoftReset, emitSoftReset} from '#/state/events'
+import {listenSoftReset} from '#/state/events'
import {truncateAndInvalidate} from '#/state/queries/util'
import {TabState, getTabState, getRootNavigation} from '#/lib/routes/helpers'
import {isNative} from '#/platform/detection'
@@ -47,10 +41,8 @@ export function FeedPage({
renderEndOfFeed?: () => JSX.Element
}) {
const {hasSession} = useSession()
- const pal = usePalette('default')
const {_} = useLingui()
const navigation = useNavigation()
- const {isDesktop} = useWebMediaQueries()
const queryClient = useQueryClient()
const {openComposer} = useComposerControls()
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
@@ -99,63 +91,6 @@ export function FeedPage({
setHasNew(false)
}, [scrollToTop, feed, queryClient, setHasNew])
- const ListHeaderComponent = React.useCallback(() => {
- if (isDesktop) {
- return (
-
-
- Bluesky{' '}
- {hasNew && (
-
- )}
- >
- }
- onPress={emitSoftReset}
- />
- {hasSession && (
-
- }
- />
- )}
-
- )
- }
- return <>>
- }, [isDesktop, pal.view, pal.text, pal.textLight, hasNew, _, hasSession])
-
return (
@@ -171,7 +106,6 @@ export function FeedPage({
onHasNew={setHasNew}
renderEmptyState={renderEmptyState}
renderEndOfFeed={renderEndOfFeed}
- ListHeaderComponent={ListHeaderComponent}
headerOffset={headerOffset}
/>
@@ -200,21 +134,12 @@ export function FeedPage({
function useHeaderOffset() {
const {isDesktop, isTablet} = useWebMediaQueries()
const {fontScale} = useWindowDimensions()
- const {hasSession} = useSession()
if (isDesktop || isTablet) {
return 0
}
- if (hasSession) {
- const navBarPad = 16
- const navBarText = 21 * fontScale
- const tabBarPad = 20 + 3 // nav bar padding + border
- const tabBarText = 16 * fontScale
- const magic = 7 * fontScale
- return navBarPad + navBarText + tabBarPad + tabBarText + magic
- } else {
- const navBarPad = 16
- const navBarText = 21 * fontScale
- const magic = 4 * fontScale
- return navBarPad + navBarText + magic
- }
+ const navBarHeight = 42
+ const tabBarPad = 10 + 10 + 3 // padding + border
+ const normalLineHeight = 1.2
+ const tabBarText = 16 * normalLineHeight * fontScale
+ return navBarHeight + tabBarPad + tabBarText
}
diff --git a/src/view/com/home/HomeHeader.tsx b/src/view/com/home/HomeHeader.tsx
index 5ffa31f392..aa3ecb7fc2 100644
--- a/src/view/com/home/HomeHeader.tsx
+++ b/src/view/com/home/HomeHeader.tsx
@@ -1,8 +1,7 @@
import React from 'react'
import {RenderTabBarFnProps} from 'view/com/pager/Pager'
import {HomeHeaderLayout} from './HomeHeaderLayout'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {usePinnedFeedsInfos} from '#/state/queries/feed'
+import {FeedSourceInfo} from '#/state/queries/feed'
import {useNavigation} from '@react-navigation/native'
import {NavigationProp} from 'lib/routes/types'
import {isWeb} from 'platform/detection'
@@ -10,25 +9,22 @@ import {TabBar} from '../pager/TabBar'
import {usePalette} from '#/lib/hooks/usePalette'
export function HomeHeader(
- props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
-) {
- const {isDesktop} = useWebMediaQueries()
- if (isDesktop) {
- return null
- }
- return
-}
-
-export function HomeHeaderInner(
- props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
+ props: RenderTabBarFnProps & {
+ testID?: string
+ onPressSelected: () => void
+ feeds: FeedSourceInfo[]
+ },
) {
+ const {feeds} = props
const navigation = useNavigation()
- const {feeds, hasPinnedCustom} = usePinnedFeedsInfos()
const pal = usePalette('default')
+ const hasPinnedCustom = React.useMemo(() => {
+ return feeds.some(tab => tab.uri !== '')
+ }, [feeds])
+
const items = React.useMemo(() => {
const pinnedNames = feeds.map(f => f.displayName)
-
if (!hasPinnedCustom) {
return pinnedNames.concat('Feeds āØ')
}
@@ -56,7 +52,7 @@ export function HomeHeaderInner(
)
return (
-
+
{children}
+ return
} else {
- return {children}
+ return
}
}
-function HomeHeaderLayoutTablet({children}: {children: React.ReactNode}) {
+function HomeHeaderLayoutDesktopAndTablet({
+ children,
+ tabBarAnchor,
+}: {
+ children: React.ReactNode
+ tabBarAnchor: JSX.Element | null | undefined
+}) {
const pal = usePalette('default')
const {headerMinimalShellTransform} = useMinimalShellMode()
const {headerHeight} = useShellLayout()
+ const {_} = useLingui()
return (
- // @ts-ignore the type signature for transform wrong here, translateX and translateY need to be in separate objects -prf
- {
- headerHeight.value = e.nativeEvent.layout.height
- }}>
- {children}
-
+ <>
+
+
+
+
+
+
+
+
+
+ {tabBarAnchor}
+ {
+ headerHeight.value = e.nativeEvent.layout.height
+ }}
+ style={[
+ pal.view,
+ pal.border,
+ styles.bar,
+ styles.tabBar,
+ headerMinimalShellTransform,
+ ]}>
+ {children}
+
+ >
)
}
const styles = StyleSheet.create({
- tabBar: {
+ bar: {
// @ts-ignore Web only
- position: 'sticky',
- zIndex: 1,
- // @ts-ignore Web only -prf
left: 'calc(50% - 300px)',
width: 600,
- top: 0,
- flexDirection: 'row',
- alignItems: 'center',
borderLeftWidth: 1,
borderRightWidth: 1,
},
+ topBar: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingHorizontal: 18,
+ paddingTop: 16,
+ paddingBottom: 8,
+ },
+ tabBar: {
+ // @ts-ignore Web only
+ position: 'sticky',
+ top: 0,
+ flexDirection: 'column',
+ alignItems: 'center',
+ borderLeftWidth: 1,
+ borderRightWidth: 1,
+ zIndex: 1,
+ },
})
diff --git a/src/view/com/home/HomeHeaderLayoutMobile.tsx b/src/view/com/home/HomeHeaderLayoutMobile.tsx
index 6c4b911f07..d7b7231c60 100644
--- a/src/view/com/home/HomeHeaderLayoutMobile.tsx
+++ b/src/view/com/home/HomeHeaderLayoutMobile.tsx
@@ -23,6 +23,7 @@ export function HomeHeaderLayoutMobile({
children,
}: {
children: React.ReactNode
+ tabBarAnchor: JSX.Element | null | undefined
}) {
const pal = usePalette('default')
const {_} = useLingui()
@@ -103,7 +104,6 @@ const styles = StyleSheet.create({
right: 0,
top: 0,
flexDirection: 'column',
- borderBottomWidth: 1,
},
topBar: {
flexDirection: 'row',
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index 822e1020c0..a9207607b1 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -19,7 +19,6 @@ import * as EditImageModal from './AltImage'
import * as ReportModal from './report/Modal'
import * as DeleteAccountModal from './DeleteAccount'
import * as ChangeHandleModal from './ChangeHandle'
-import * as WaitlistModal from './Waitlist'
import * as InviteCodesModal from './InviteCodes'
import * as AddAppPassword from './AddAppPasswords'
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
@@ -103,9 +102,6 @@ export function ModalsContainer() {
} else if (activeModal?.name === 'change-handle') {
snapPoints = ChangeHandleModal.snapPoints
element =
- } else if (activeModal?.name === 'waitlist') {
- snapPoints = WaitlistModal.snapPoints
- element =
} else if (activeModal?.name === 'invite-codes') {
snapPoints = InviteCodesModal.snapPoints
element =
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 2d2a6f6e6e..347057062e 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -21,7 +21,6 @@ import * as CropImageModal from './crop-image/CropImage.web'
import * as AltTextImageModal from './AltImage'
import * as EditImageModal from './EditImage'
import * as ChangeHandleModal from './ChangeHandle'
-import * as WaitlistModal from './Waitlist'
import * as InviteCodesModal from './InviteCodes'
import * as AddAppPassword from './AddAppPasswords'
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
@@ -100,8 +99,6 @@ function Modal({modal}: {modal: ModalIface}) {
element =
} else if (modal.name === 'change-handle') {
element =
- } else if (modal.name === 'waitlist') {
- element =
} else if (modal.name === 'invite-codes') {
element =
} else if (modal.name === 'add-app-password') {
diff --git a/src/view/com/modals/Waitlist.tsx b/src/view/com/modals/Waitlist.tsx
deleted file mode 100644
index 263dd27a2f..0000000000
--- a/src/view/com/modals/Waitlist.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-import React from 'react'
-import {
- ActivityIndicator,
- StyleSheet,
- TouchableOpacity,
- View,
-} from 'react-native'
-import {TextInput} from './util'
-import {
- FontAwesomeIcon,
- FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import LinearGradient from 'react-native-linear-gradient'
-import {Text} from '../util/text/Text'
-import {s, gradients} from 'lib/styles'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useTheme} from 'lib/ThemeContext'
-import {ErrorMessage} from '../util/error/ErrorMessage'
-import {cleanError} from 'lib/strings/errors'
-import {Trans, msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useModalControls} from '#/state/modals'
-
-export const snapPoints = ['80%']
-
-export function Component({}: {}) {
- const pal = usePalette('default')
- const theme = useTheme()
- const {_} = useLingui()
- const {closeModal} = useModalControls()
- const [email, setEmail] = React.useState('')
- const [isEmailSent, setIsEmailSent] = React.useState(false)
- const [isProcessing, setIsProcessing] = React.useState(false)
- const [error, setError] = React.useState('')
-
- const onPressSignup = async () => {
- setError('')
- setIsProcessing(true)
- try {
- const res = await fetch('https://bsky.app/api/waitlist', {
- method: 'POST',
- headers: {'Content-Type': 'application/json'},
- body: JSON.stringify({email}),
- })
- const resBody = await res.json()
- if (resBody.success) {
- setIsEmailSent(true)
- } else {
- setError(
- resBody.error ||
- _(msg`Something went wrong. Check your email and try again.`),
- )
- }
- } catch (e: any) {
- setError(cleanError(e))
- }
- setIsProcessing(false)
- }
- const onCancel = () => {
- closeModal()
- }
-
- return (
-
-
-
- Join the waitlist
-
-
-
- Bluesky uses invites to build a healthier community. If you don't
- know anybody with an invite, you can sign up for the waitlist and
- we'll send one soon.
-
-
-
- {error ? (
-
-
-
- ) : undefined}
- {isProcessing ? (
-
-
-
- ) : isEmailSent ? (
-
-
-
-
- Your email has been saved! We'll be in touch soon.
-
-
-
- ) : (
- <>
-
-
-
- Join Waitlist
-
-
-
-
-
- Cancel
-
-
- >
- )}
-
-
- )
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- innerContainer: {
- paddingBottom: 20,
- },
- title: {
- textAlign: 'center',
- marginTop: 12,
- marginBottom: 12,
- },
- description: {
- textAlign: 'center',
- paddingHorizontal: 22,
- marginBottom: 10,
- },
- textInput: {
- borderWidth: 1,
- borderRadius: 6,
- paddingHorizontal: 16,
- paddingVertical: 12,
- fontSize: 20,
- marginHorizontal: 20,
- },
- btn: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- borderRadius: 32,
- padding: 14,
- marginHorizontal: 20,
- },
- error: {
- borderRadius: 6,
- marginHorizontal: 20,
- marginBottom: 20,
- },
-})
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index 7567b264ec..3d99146ead 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -228,6 +228,7 @@ let FeedItem = ({
text={sanitizeDisplayName(
authors[0].displayName || authors[0].handle,
)}
+ disableMismatchWarning
/>
{authors.length > 1 ? (
<>
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index dadcfcebd9..ff8acd60cc 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -4,8 +4,8 @@ import {Text} from '../util/text/Text'
import {PressableWithHover} from '../util/PressableWithHover'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {isWeb} from 'platform/detection'
import {DraggableScrollView} from './DraggableScrollView'
+import {isNative} from '#/platform/detection'
export interface TabBarProps {
testID?: string
@@ -16,6 +16,10 @@ export interface TabBarProps {
onPressSelected?: (index: number) => void
}
+// How much of the previous/next item we're showing
+// to give the user a hint there's more to scroll.
+const OFFSCREEN_ITEM_WIDTH = 20
+
export function TabBar({
testID,
selectedPage,
@@ -26,19 +30,68 @@ export function TabBar({
}: TabBarProps) {
const pal = usePalette('default')
const scrollElRef = useRef(null)
+ const itemRefs = useRef>([])
const [itemXs, setItemXs] = useState([])
const indicatorStyle = useMemo(
() => ({borderBottomColor: indicatorColor || pal.colors.link}),
[indicatorColor, pal],
)
const {isDesktop, isTablet} = useWebMediaQueries()
+ const styles = isDesktop || isTablet ? desktopStyles : mobileStyles
- // scrolls to the selected item when the page changes
useEffect(() => {
- scrollElRef.current?.scrollTo({
- x: itemXs[selectedPage] || 0,
- })
- }, [scrollElRef, itemXs, selectedPage])
+ if (isNative) {
+ // On native, the primary interaction is swiping.
+ // We adjust the scroll little by little on every tab change.
+ // Scroll into view but keep the end of the previous item visible.
+ let x = itemXs[selectedPage] || 0
+ x = Math.max(0, x - OFFSCREEN_ITEM_WIDTH)
+ scrollElRef.current?.scrollTo({x})
+ } else {
+ // On the web, the primary interaction is tapping.
+ // Scrolling under tap feels disorienting so only adjust the scroll offset
+ // when tapping on an item out of view--and we adjust by almost an entire page.
+ const parent = scrollElRef?.current?.getScrollableNode?.()
+ if (!parent) {
+ return
+ }
+ const parentRect = parent.getBoundingClientRect()
+ if (!parentRect) {
+ return
+ }
+ const {
+ left: parentLeft,
+ right: parentRight,
+ width: parentWidth,
+ } = parentRect
+ const child = itemRefs.current[selectedPage]
+ if (!child) {
+ return
+ }
+ const childRect = child.getBoundingClientRect?.()
+ if (!childRect) {
+ return
+ }
+ const {left: childLeft, right: childRight, width: childWidth} = childRect
+ let dx = 0
+ if (childRight >= parentRight) {
+ dx += childRight - parentRight
+ dx += parentWidth - childWidth - OFFSCREEN_ITEM_WIDTH
+ } else if (childLeft <= parentLeft) {
+ dx -= parentLeft - childLeft
+ dx -= parentWidth - childWidth - OFFSCREEN_ITEM_WIDTH
+ }
+ let x = parent.scrollLeft + dx
+ x = Math.max(0, x)
+ x = Math.min(x, parent.scrollWidth - parentWidth)
+ if (dx !== 0) {
+ parent.scroll({
+ left: x,
+ behavior: 'smooth',
+ })
+ }
+ }
+ }, [scrollElRef, itemXs, selectedPage, styles])
const onPressItem = useCallback(
(index: number) => {
@@ -63,8 +116,6 @@ export function TabBar({
[],
)
- const styles = isDesktop || isTablet ? desktopStyles : mobileStyles
-
return (
(itemRefs.current[i] = node)}
onLayout={e => onItemLayout(e, i)}
- style={[styles.item, selected && indicatorStyle]}
+ style={styles.item}
hoverStyle={pal.viewLight}
onPress={() => onPressItem(i)}>
-
- {item}
-
+
+
+ {item}
+
+
)
})}
+
)
}
@@ -103,18 +158,25 @@ const desktopStyles = StyleSheet.create({
width: 598,
},
contentContainer: {
- columnGap: 8,
- marginLeft: 14,
- paddingRight: 14,
+ paddingHorizontal: 0,
backgroundColor: 'transparent',
},
item: {
paddingTop: 14,
+ paddingHorizontal: 14,
+ justifyContent: 'center',
+ },
+ itemInner: {
paddingBottom: 12,
- paddingHorizontal: 10,
borderBottomWidth: 3,
borderBottomColor: 'transparent',
- justifyContent: 'center',
+ },
+ outerBottomBorder: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ bottom: -1,
+ borderBottomWidth: 1,
},
})
@@ -123,17 +185,24 @@ const mobileStyles = StyleSheet.create({
flexDirection: 'row',
},
contentContainer: {
- columnGap: isWeb ? 0 : 20,
- marginLeft: isWeb ? 0 : 18,
- paddingRight: isWeb ? 0 : 36,
backgroundColor: 'transparent',
+ paddingHorizontal: 8,
},
item: {
paddingTop: 10,
- paddingBottom: 10,
- paddingHorizontal: isWeb ? 8 : 0,
- borderBottomWidth: 3,
- borderBottomColor: 'transparent',
+ paddingHorizontal: 10,
justifyContent: 'center',
},
+ itemInner: {
+ paddingBottom: 10,
+ borderBottomWidth: 3,
+ borderBottomColor: 'transparent',
+ },
+ outerBottomBorder: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ bottom: -1,
+ borderBottomWidth: 1,
+ },
})
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 280f7208f1..bac7018c34 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -438,6 +438,7 @@ function PostThreadLoaded({
// @ts-ignore our .web version only -prf
desktopFixedHeight
removeClippedSubviews={isAndroid ? false : undefined}
+ windowSize={11}
/>
)
}
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 004c3ee6d4..51e08a1acb 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -94,6 +94,8 @@ export function PostThreadItem({
if (richText && moderation) {
return (
) : undefined}
@@ -489,9 +493,11 @@ let PostThreadItemLoaded = ({
{richText?.text ? (
) : undefined}
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index 719a8592e6..37092d4d76 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -190,10 +190,12 @@ function PostInner({
{richText.text ? (
) : undefined}
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index 54d8aa2240..cd3e98785d 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -32,6 +32,7 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
import {FALLBACK_MARKER_POST} from '#/lib/api/feed/home'
+import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
const LOADING_ITEM = {_reactKey: '__loading__'}
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
@@ -84,6 +85,7 @@ let Feed = ({
const {_} = useLingui()
const queryClient = useQueryClient()
const {currentAccount} = useSession()
+ const initialNumToRender = useInitialNumToRender()
const [isPTRing, setIsPTRing] = React.useState(false)
const checkForNewRef = React.useRef<(() => void) | null>(null)
const lastFetchRef = React.useRef(Date.now())
@@ -327,6 +329,8 @@ let Feed = ({
desktopFixedHeight={
desktopFixedHeightOffset ? desktopFixedHeightOffset : true
}
+ initialNumToRender={initialNumToRender}
+ windowSize={11}
/>
)
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index a90ced32c2..3604f9d124 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -69,6 +69,8 @@ export function FeedItem({
if (richText && moderation) {
return (
) : undefined}
diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx
index e4e02e4d76..97efb9b14b 100644
--- a/src/view/com/util/Link.tsx
+++ b/src/view/com/util/Link.tsx
@@ -162,7 +162,7 @@ export const TextLink = memo(function TextLink({
dataSet,
title,
onPress,
- warnOnMismatchingLabel,
+ disableMismatchWarning,
navigationAction,
...orgProps
}: {
@@ -175,7 +175,7 @@ export const TextLink = memo(function TextLink({
lineHeight?: number
dataSet?: any
title?: string
- warnOnMismatchingLabel?: boolean
+ disableMismatchWarning?: boolean
navigationAction?: 'push' | 'replace' | 'navigate'
} & TextProps) {
const {...props} = useLinkProps({to: sanitizeUrl(href)})
@@ -183,14 +183,14 @@ export const TextLink = memo(function TextLink({
const {openModal, closeModal} = useModalControls()
const openLink = useOpenLink()
- if (warnOnMismatchingLabel && typeof text !== 'string') {
+ if (!disableMismatchWarning && typeof text !== 'string') {
console.error('Unable to detect mismatching label')
}
props.onPress = React.useCallback(
(e?: Event) => {
const requiresWarning =
- warnOnMismatchingLabel &&
+ !disableMismatchWarning &&
linkRequiresWarning(href, typeof text === 'string' ? text : '')
if (requiresWarning) {
e?.preventDefault?.()
@@ -230,7 +230,7 @@ export const TextLink = memo(function TextLink({
navigation,
href,
text,
- warnOnMismatchingLabel,
+ disableMismatchWarning,
navigationAction,
openLink,
],
diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx
index 29bad2db8b..936bac198d 100644
--- a/src/view/com/util/List.web.tsx
+++ b/src/view/com/util/List.web.tsx
@@ -172,7 +172,7 @@ function ListImpl(
(
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
const styles = StyleSheet.create({
- contentContainer: {
+ sideBorders: {
borderLeftWidth: 1,
borderRightWidth: 1,
},
diff --git a/src/view/com/util/MainScrollProvider.tsx b/src/view/com/util/MainScrollProvider.tsx
index 2c90e33ff1..01b8a954d5 100644
--- a/src/view/com/util/MainScrollProvider.tsx
+++ b/src/view/com/util/MainScrollProvider.tsx
@@ -20,12 +20,14 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const setMode = useSetMinimalShellMode()
const startDragOffset = useSharedValue(null)
const startMode = useSharedValue(null)
+ const didJustRestoreScroll = useSharedValue(false)
useEffect(() => {
if (isWeb) {
return listenToForcedWindowScroll(() => {
startDragOffset.value = null
startMode.value = null
+ didJustRestoreScroll.value = true
})
}
})
@@ -86,6 +88,11 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
mode.value = newValue
}
} else {
+ if (didJustRestoreScroll.value) {
+ didJustRestoreScroll.value = false
+ // Don't hide/show navbar based on scroll restoratoin.
+ return
+ }
// On the web, we don't try to follow the drag because we don't know when it ends.
// Instead, show/hide immediately based on whether we're scrolling up or down.
const dy = e.contentOffset.y - (startDragOffset.value ?? 0)
@@ -98,7 +105,14 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
}
}
},
- [headerHeight, mode, setMode, startDragOffset, startMode],
+ [
+ headerHeight,
+ mode,
+ setMode,
+ startDragOffset,
+ startMode,
+ didJustRestoreScroll,
+ ],
)
return (
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx
index 1ccfcf56c5..872e10eef0 100644
--- a/src/view/com/util/ViewHeader.tsx
+++ b/src/view/com/util/ViewHeader.tsx
@@ -13,11 +13,13 @@ import Animated from 'react-native-reanimated'
import {useSetDrawerOpen} from '#/state/shell'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {useTheme} from '#/alf'
const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
export function ViewHeader({
title,
+ subtitle,
canGoBack,
showBackButton = true,
hideOnScroll,
@@ -26,6 +28,7 @@ export function ViewHeader({
renderButton,
}: {
title: string
+ subtitle?: string
canGoBack?: boolean
showBackButton?: boolean
hideOnScroll?: boolean
@@ -39,6 +42,7 @@ export function ViewHeader({
const navigation = useNavigation()
const {track} = useAnalytics()
const {isDesktop, isTablet} = useWebMediaQueries()
+ const t = useTheme()
const onPressBack = React.useCallback(() => {
if (navigation.canGoBack()) {
@@ -71,42 +75,60 @@ export function ViewHeader({
return (
- {showBackButton ? (
-
- {canGoBack ? (
-
- ) : !isTablet ? (
-
+
+
+ {showBackButton ? (
+
+ {canGoBack ? (
+
+ ) : !isTablet ? (
+
+ ) : null}
+
) : null}
-
- ) : null}
-
-
- {title}
-
+
+
+ {title}
+
+
+ {renderButton ? (
+ renderButton()
+ ) : showBackButton ? (
+
+ ) : null}
+
+ {subtitle ? (
+
+
+ {subtitle}
+
+
+ ) : undefined}
- {renderButton ? (
- renderButton()
- ) : showBackButton ? (
-
- ) : null}
)
}
@@ -185,7 +207,6 @@ function Container({
const styles = StyleSheet.create({
header: {
flexDirection: 'row',
- alignItems: 'center',
paddingHorizontal: 12,
paddingVertical: 6,
width: '100%',
@@ -207,12 +228,14 @@ const styles = StyleSheet.create({
titleContainer: {
marginLeft: 'auto',
marginRight: 'auto',
- paddingRight: 10,
+ alignItems: 'center',
},
title: {
fontWeight: 'bold',
},
-
+ subtitle: {
+ fontSize: 13,
+ },
backBtn: {
width: 30,
height: 30,
diff --git a/src/view/com/util/Views.d.ts b/src/view/com/util/Views.d.ts
index 6a90cc229b..16713921fb 100644
--- a/src/view/com/util/Views.d.ts
+++ b/src/view/com/util/Views.d.ts
@@ -5,4 +5,6 @@ export function CenteredView({
style,
sideBorders,
...props
-}: React.PropsWithChildren)
+}: React.PropsWithChildren<
+ ViewProps & {sideBorders?: boolean; topBorder?: boolean}
+>)
diff --git a/src/view/com/util/Views.web.tsx b/src/view/com/util/Views.web.tsx
index db3b9de0d8..ae165077ca 100644
--- a/src/view/com/util/Views.web.tsx
+++ b/src/view/com/util/Views.web.tsx
@@ -32,8 +32,11 @@ interface AddedProps {
export function CenteredView({
style,
sideBorders,
+ topBorder,
...props
-}: React.PropsWithChildren) {
+}: React.PropsWithChildren<
+ ViewProps & {sideBorders?: boolean; topBorder?: boolean}
+>) {
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
if (!isMobile) {
@@ -46,6 +49,12 @@ export function CenteredView({
})
style = addStyle(style, pal.border)
}
+ if (topBorder) {
+ style = addStyle(style, {
+ borderTopWidth: 1,
+ })
+ style = addStyle(style, pal.border)
+ }
return
}
diff --git a/src/view/com/util/forms/DateInput.tsx b/src/view/com/util/forms/DateInput.tsx
index c5f0afc8fc..0104562aa5 100644
--- a/src/view/com/util/forms/DateInput.tsx
+++ b/src/view/com/util/forms/DateInput.tsx
@@ -1,8 +1,5 @@
import React, {useState, useCallback} from 'react'
import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
-import DateTimePicker, {
- DateTimePickerEvent,
-} from '@react-native-community/datetimepicker'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
@@ -14,6 +11,7 @@ import {TypographyVariant} from 'lib/ThemeContext'
import {useTheme} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette'
import {getLocales} from 'expo-localization'
+import DatePicker from 'react-native-date-picker'
const LOCALE = getLocales()[0]
@@ -43,11 +41,9 @@ export function DateInput(props: Props) {
}, [props.handleAsUTC])
const onChangeInternal = useCallback(
- (event: DateTimePickerEvent, date: Date | undefined) => {
+ (date: Date) => {
setShow(false)
- if (date) {
- props.onChange(date)
- }
+ props.onChange(date)
},
[setShow, props],
)
@@ -56,6 +52,10 @@ export function DateInput(props: Props) {
setShow(true)
}, [setShow])
+ const onCancel = useCallback(() => {
+ setShow(false)
+ }, [])
+
return (
{isAndroid && (
@@ -80,15 +80,17 @@ export function DateInput(props: Props) {
)}
{(isIOS || show) && (
- {
return (
) {
const pal = usePalette('default')
const theme = useTheme()
@@ -119,7 +122,8 @@ export function NativeDropdown({
accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint}
onPress={() => setOpen(o => !o)}
- hitSlop={HITSLOP_10}>
+ hitSlop={HITSLOP_10}
+ style={triggerStyle}>
{children}
@@ -232,6 +236,10 @@ const styles = StyleSheet.create({
paddingLeft: 12,
paddingRight: 12,
borderRadius: 8,
+ fontFamily:
+ '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
+ outline: 0,
+ border: 0,
},
itemTitle: {
fontSize: 16,
diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx
index ccfaff301d..00dfe6a7ac 100644
--- a/src/view/com/util/forms/PostDropdownBtn.tsx
+++ b/src/view/com/util/forms/PostDropdownBtn.tsx
@@ -36,6 +36,7 @@ import {isWeb} from '#/platform/detection'
import {richTextToString} from '#/lib/strings/rich-text-helpers'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
import {NEW_REPORT_DIALOG_ENABLED} from '#/lib/build-flags'
+import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
let PostDropdownBtn = ({
testID,
@@ -68,6 +69,7 @@ let PostDropdownBtn = ({
const openLink = useOpenLink()
const control = useReportDialogControl()
const navigation = useNavigation()
+ const {mutedWordsDialogControl} = useGlobalDialogsControlContext()
const rootUri = record.reply?.root?.uri || postUri
const isThreadMuted = mutedThreads.includes(rootUri)
@@ -211,6 +213,20 @@ let PostDropdownBtn = ({
web: 'comment-slash',
},
},
+ hasSession && {
+ label: _(msg`Mute words & tags`),
+ onPress() {
+ mutedWordsDialogControl.open()
+ },
+ testID: 'postDropdownMuteWordsBtn',
+ icon: {
+ ios: {
+ name: 'speaker.slash',
+ },
+ android: 'ic_lock_silent_mode',
+ web: 'filter',
+ },
+ },
hasSession &&
!isAuthor &&
!isPostHidden && {
diff --git a/src/view/com/util/text/RichText.tsx b/src/view/com/util/text/RichText.tsx
index b6d461224c..f4ade30e55 100644
--- a/src/view/com/util/text/RichText.tsx
+++ b/src/view/com/util/text/RichText.tsx
@@ -7,6 +7,9 @@ import {lh} from 'lib/styles'
import {toShortUrl} from 'lib/strings/url-helpers'
import {useTheme, TypographyVariant} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette'
+import {makeTagLink} from 'lib/routes/links'
+import {TagMenu, useTagMenuControl} from '#/components/TagMenu'
+import {isNative} from '#/platform/detection'
const WORD_WRAP = {wordWrap: 1}
@@ -82,6 +85,7 @@ export function RichText({
for (const segment of richText.segments()) {
const link = segment.link
const mention = segment.mention
+ const tag = segment.tag
if (
!noLinks &&
mention &&
@@ -110,11 +114,25 @@ export function RichText({
href={link.uri}
style={[style, lineHeightStyle, pal.link, {pointerEvents: 'auto'}]}
dataSet={WORD_WRAP}
- warnOnMismatchingLabel
selectable={selectable}
/>,
)
}
+ } else if (
+ !noLinks &&
+ tag &&
+ AppBskyRichtextFacet.validateTag(tag).success
+ ) {
+ els.push(
+ ,
+ )
} else {
els.push(segment.text)
}
@@ -133,3 +151,50 @@ export function RichText({
)
}
+
+function RichTextTag({
+ text: tag,
+ type,
+ style,
+ lineHeightStyle,
+ selectable,
+}: {
+ text: string
+ type?: TypographyVariant
+ style?: StyleProp
+ lineHeightStyle?: TextStyle
+ selectable?: boolean
+}) {
+ const pal = usePalette('default')
+ const control = useTagMenuControl()
+
+ const open = React.useCallback(() => {
+ control.open()
+ }, [control])
+
+ return (
+
+
+ {isNative ? (
+
+ ) : (
+
+ {tag}
+
+ )}
+
+
+ )
+}
diff --git a/src/view/icons/index.tsx b/src/view/icons/index.tsx
index b7bbf16009..ede1e63355 100644
--- a/src/view/icons/index.tsx
+++ b/src/view/icons/index.tsx
@@ -103,6 +103,7 @@ import {faUsersSlash} from '@fortawesome/free-solid-svg-icons/faUsersSlash'
import {faX} from '@fortawesome/free-solid-svg-icons/faX'
import {faXmark} from '@fortawesome/free-solid-svg-icons/faXmark'
import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown'
+import {faFilter} from '@fortawesome/free-solid-svg-icons/faFilter'
library.add(
faAddressCard,
@@ -208,4 +209,5 @@ library.add(
faX,
faXmark,
faChevronDown,
+ faFilter,
)
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 856c237f6e..99ac8c44af 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -17,11 +17,12 @@ import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
import {emitSoftReset} from '#/state/events'
import {useSession} from '#/state/session'
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
+import {useSetTitle} from '#/lib/hooks/useSetTitle'
type Props = NativeStackScreenProps
export function HomeScreen(props: Props) {
const {data: preferences} = usePreferencesQuery()
- const {feeds: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
+ const {data: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
usePinnedFeedsInfos()
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
return (
@@ -66,6 +67,8 @@ function HomeScreenReady({
const selectedIndex = Math.max(0, maybeFoundIndex)
const selectedFeed = allFeeds[selectedIndex]
+ useSetTitle(pinnedFeedInfos[selectedIndex]?.displayName)
+
const pagerRef = React.useRef(null)
const lastPagerReportedIndexRef = React.useRef(selectedIndex)
React.useLayoutEffect(() => {
@@ -120,14 +123,14 @@ function HomeScreenReady({
return (
)
},
- [onPressSelected],
+ [onPressSelected, pinnedFeedInfos],
)
const renderFollowingEmptyState = React.useCallback(() => {
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index 7dae1c9639..36c73fefb3 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -488,6 +488,8 @@ const styles = StyleSheet.create({
container: {
flexDirection: 'column',
height: '100%',
+ // @ts-ignore Web-only.
+ overflowAnchor: 'none', // Fixes jumps when switching tabs while scrolled down.
},
loading: {
paddingVertical: 10,
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index d86b569e25..9e98757efa 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -60,7 +60,7 @@ import {
import {logger} from '#/logger'
import {useAnalytics} from '#/lib/analytics/analytics'
import {listenSoftReset} from '#/state/events'
-import {atoms as a} from '#/alf'
+import {atoms as a, useTheme} from '#/alf'
const SECTION_TITLES_CURATE = ['Posts', 'About']
const SECTION_TITLES_MOD = ['About']
@@ -699,6 +699,7 @@ const AboutSection = React.forwardRef(
ref,
) {
const pal = usePalette('default')
+ const t = useTheme()
const {_} = useLingui()
const {isMobile} = useWebMediaQueries()
const {currentAccount} = useSession()
@@ -792,7 +793,7 @@ const AboutSection = React.forwardRef(
paddingBottom: isMobile ? 14 : 18,
},
]}>
-
+
Users
{isOwner && (
@@ -817,14 +818,18 @@ const AboutSection = React.forwardRef(
)
}, [
- pal,
- list,
isMobile,
+ pal.border,
+ pal.textLight,
+ pal.colors.link,
+ pal.link,
descriptionRT,
isCurateList,
isOwner,
- onPressAddUser,
+ list.creator,
+ t.atoms.text,
_,
+ onPressAddUser,
])
const renderEmptyState = useCallback(() => {
diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx
index 142726701e..42eec53d31 100644
--- a/src/view/screens/Search/Search.tsx
+++ b/src/view/screens/Search/Search.tsx
@@ -16,7 +16,7 @@ import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
-import {useFocusEffect} from '@react-navigation/native'
+import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {logger} from '#/logger'
import {
@@ -53,6 +53,7 @@ import {listenSoftReset} from '#/state/events'
import {s} from '#/lib/styles'
import AsyncStorage from '@react-native-async-storage/async-storage'
import {augmentSearchQuery} from '#/lib/strings/helpers'
+import {NavigationProp} from '#/lib/routes/types'
function Loader() {
const pal = usePalette('default')
@@ -448,6 +449,7 @@ export function SearchScreenInner({
export function SearchScreen(
props: NativeStackScreenProps,
) {
+ const navigation = useNavigation()
const theme = useTheme()
const textInput = React.useRef(null)
const {_} = useLingui()
@@ -472,6 +474,27 @@ export function SearchScreen(
React.useState(false)
const [searchHistory, setSearchHistory] = React.useState([])
+ /**
+ * The Search screen's `q` param
+ */
+ const queryParam = props.route?.params?.q
+
+ /**
+ * If `true`, this means we received new instructions from the router. This
+ * is handled in a effect, and used to update the value of `query` locally
+ * within this screen.
+ */
+ const routeParamsMismatch = queryParam && queryParam !== query
+
+ React.useEffect(() => {
+ if (queryParam && routeParamsMismatch) {
+ // reset immediately and let local state take over
+ navigation.setParams({q: ''})
+ // update query for next search
+ setQuery(queryParam)
+ }
+ }, [queryParam, routeParamsMismatch, navigation])
+
React.useEffect(() => {
const loadSearchHistory = async () => {
try {
@@ -774,6 +797,8 @@ export function SearchScreen(
)}
+ ) : routeParamsMismatch ? (
+
) : (
)}
diff --git a/src/view/screens/Storybook/Links.tsx b/src/view/screens/Storybook/Links.tsx
index 3f18069069..f9ecfba554 100644
--- a/src/view/screens/Storybook/Links.tsx
+++ b/src/view/screens/Storybook/Links.tsx
@@ -4,7 +4,7 @@ import {View} from 'react-native'
import {useTheme, atoms as a} from '#/alf'
import {ButtonText} from '#/components/Button'
import {InlineLink, Link} from '#/components/Link'
-import {H1, H3, Text} from '#/components/Typography'
+import {H1, Text} from '#/components/Typography'
export function Links() {
const t = useTheme()
@@ -13,31 +13,19 @@ export function Links() {
Links
-
- External
+
+ https://google.com
-
- External with custom children
+
+ External with custom children (google.com)
- External with custom children
+ Internal (bsky.social)
-
- https://bsky.social
-
-
- Internal
+
+ Internal (bsky.app)
+
+
+
+ {({state, props}) => {
+ return (
+
+ Open
+
+ )
+ }}
+
+
+
+
+ {}}>
+
+ Click me
+
+
+ menuControl.close()}>
+ Another item
+
+
+
+
+
+
+ {}}>
+
+ Click me
+
+
+ menuControl.close()}>
+ Another item
+
+
+
+
+
+ {}}>
+
+ Click me
+
+
+
+
+
+ )
+}
diff --git a/src/view/screens/Storybook/Palette.tsx b/src/view/screens/Storybook/Palette.tsx
index 900754681c..42000aa810 100644
--- a/src/view/screens/Storybook/Palette.tsx
+++ b/src/view/screens/Storybook/Palette.tsx
@@ -1,7 +1,6 @@
import React from 'react'
import {View} from 'react-native'
-import * as tokens from '#/alf/tokens'
import {atoms as a, useTheme} from '#/alf'
export function Palette() {
@@ -28,79 +27,79 @@ export function Palette() {
@@ -108,153 +107,159 @@ export function Palette() {
-
-
+
+
diff --git a/src/view/screens/Storybook/Typography.tsx b/src/view/screens/Storybook/Typography.tsx
index 8ee4270b20..f0d67c5281 100644
--- a/src/view/screens/Storybook/Typography.tsx
+++ b/src/view/screens/Storybook/Typography.tsx
@@ -22,12 +22,14 @@ export function Typography() {
atoms.text_2xs
diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx
index 56cfbfaf98..3a2e2f3696 100644
--- a/src/view/screens/Storybook/index.tsx
+++ b/src/view/screens/Storybook/index.tsx
@@ -16,6 +16,7 @@ import {Dialogs} from './Dialogs'
import {Breakpoints} from './Breakpoints'
import {Shadows} from './Shadows'
import {Icons} from './Icons'
+import {Menus} from './Menus'
export function Storybook() {
const t = useTheme()
@@ -84,6 +85,8 @@ export function Storybook() {
+
+
diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx
index d37ff4fb7c..1937fcb6ea 100644
--- a/src/view/shell/Composer.tsx
+++ b/src/view/shell/Composer.tsx
@@ -55,6 +55,8 @@ export const Composer = observer(function ComposerImpl({
onPost={state.onPost}
quote={state.quote}
mention={state.mention}
+ text={state.text}
+ imageUris={state.imageUris}
/>
)
diff --git a/src/view/shell/Composer.web.tsx b/src/view/shell/Composer.web.tsx
index 99e659d62d..00233f66af 100644
--- a/src/view/shell/Composer.web.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -9,7 +9,7 @@ import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
import {
EmojiPicker,
EmojiPickerState,
-} from 'view/com/composer/text-input/web/EmojiPicker.web.tsx'
+} from 'view/com/composer/text-input/web/EmojiPicker.web'
const BOTTOM_BAR_HEIGHT = 61
@@ -69,6 +69,7 @@ export function Composer({}: {winHeight: number}) {
onPost={state.onPost}
mention={state.mention}
openPicker={onOpenPicker}
+ text={state.text}
/>
diff --git a/src/view/shell/desktop/Feeds.tsx b/src/view/shell/desktop/Feeds.tsx
index c3b1caa354..f447490b36 100644
--- a/src/view/shell/desktop/Feeds.tsx
+++ b/src/view/shell/desktop/Feeds.tsx
@@ -15,7 +15,7 @@ import {emitSoftReset} from '#/state/events'
export function DesktopFeeds() {
const pal = usePalette('default')
const {_} = useLingui()
- const {feeds: pinnedFeedInfos} = usePinnedFeedsInfos()
+ const {data: pinnedFeedInfos} = usePinnedFeedsInfos()
const selectedFeed = useSelectedFeed()
const setSelectedFeed = useSetSelectedFeed()
const navigation = useNavigation()
@@ -25,7 +25,9 @@ export function DesktopFeeds() {
}
return getCurrentRoute(state)
})
-
+ if (!pinnedFeedInfos) {
+ return null
+ }
return (
{pinnedFeedInfos.map(feedInfo => {
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index fbc90bfc6d..c56ba941ed 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -200,10 +200,10 @@ function ComposeBtn() {
const fetchHandle = useFetchHandle()
const getProfileHandle = async () => {
- const {routes} = getState()
- const currentRoute = routes[routes.length - 1]
+ const routes = getState()?.routes
+ const currentRoute = routes?.[routes?.length - 1]
- if (currentRoute.name === 'Profile') {
+ if (currentRoute?.name === 'Profile') {
let handle: string | undefined = (
currentRoute.params as CommonNavigatorParams['Profile']
).name
@@ -391,7 +391,7 @@ export function DesktopLeftNav() {
}
label={_(msg`Moderation`)}
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx
index e40865cde0..55a21e53f8 100644
--- a/src/view/shell/index.tsx
+++ b/src/view/shell/index.tsx
@@ -29,6 +29,8 @@ import {useSession} from '#/state/session'
import {useCloseAnyActiveElement} from '#/state/util'
import * as notifications from 'lib/notifications/notifications'
import {Outlet as PortalOutlet} from '#/components/Portal'
+import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
+import {useDialogStateContext} from '#/state/dialogs'
function ShellInner() {
const isDrawerOpen = useIsDrawerOpen()
@@ -54,6 +56,7 @@ function ShellInner() {
const closeAnyActiveElement = useCloseAnyActiveElement()
// start undefined
const currentAccountDid = React.useRef(undefined)
+ const {openDialogs} = useDialogStateContext()
React.useEffect(() => {
let listener = {remove() {}}
@@ -77,9 +80,21 @@ function ShellInner() {
}
}, [currentAccount])
+ /**
+ * The counterpart to `accessibilityViewIsModal` for Android. This property
+ * applies to the parent of all non-modal views, and prevents TalkBack from
+ * navigating within content beneath an open dialog.
+ *
+ * @see https://reactnative.dev/docs/accessibility#importantforaccessibility-android
+ */
+ const importantForAccessibility =
+ openDialogs.length > 0 ? 'no-hide-descendants' : undefined
+
return (
<>
-
+
+
+
>
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index 0e7767eae8..9aeb1c860f 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -16,6 +16,7 @@ import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
import {useCloseAllActiveElements} from '#/state/util'
import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
import {Outlet as PortalOutlet} from '#/components/Portal'
+import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
function ShellInner() {
const isDrawerOpen = useIsDrawerOpen()
@@ -40,6 +41,8 @@ function ShellInner() {
+
+
diff --git a/web/index.html b/web/index.html
index 992e69e053..b6e01ba4c2 100644
--- a/web/index.html
+++ b/web/index.html
@@ -48,6 +48,12 @@
scrollbar-gutter: stable both-edges;
}
+ /* Buttons and inputs have a font set by UA, so we'll have to reset that */
+ button, input, textarea {
+ font: inherit;
+ line-height: inherit;
+ }
+
/* Color theming */
/* Default will always be white */
:root {
@@ -209,6 +215,12 @@
[data-tooltip]:hover::before {
display:block;
}
+
+ /* NativeDropdown component */
+ .radix-dropdown-item:focus,
+ .nativeDropdown-item:focus {
+ outline: none;
+ }
diff --git a/yarn.lock b/yarn.lock
index 14fd49c477..4b9ba74153 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -34,6 +34,20 @@
jsonpointer "^5.0.0"
leven "^3.1.0"
+"@atproto/api@^0.10.5":
+ version "0.10.5"
+ resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.10.5.tgz#e778e2843d08690df8df81f24028a7578e9b3cb4"
+ integrity sha512-GYdST5sPKU2JnPmm8x3KqjOSlDiYXrp4GkW7bpQTVLPabnUNq5NLN6HJEoJABjjOAsaLF12rBoV+JpRb1UjNsQ==
+ dependencies:
+ "@atproto/common-web" "^0.2.3"
+ "@atproto/lexicon" "^0.3.2"
+ "@atproto/syntax" "^0.2.0"
+ "@atproto/xrpc" "^0.4.2"
+ multiformats "^9.9.0"
+ tlds "^1.234.0"
+ typed-emitter "^2.1.0"
+ zod "^3.21.4"
+
"@atproto/api@^0.9.5":
version "0.9.5"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.9.5.tgz#630e5d9520bba38d0cd348c8028ddbb73bd074f8"
@@ -231,6 +245,17 @@
multiformats "^9.9.0"
zod "^3.21.4"
+"@atproto/lexicon@^0.3.2":
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.3.2.tgz#0085a3acd3a77867b8efe188297a1bbacc55ce5c"
+ integrity sha512-kmGCkrRwpWIqmn/KO4BZwUf8Nmfndk3XvFC06V0ygCWc42g6+t4QP/6ywNW4PgqfZY0Q5aW4EuDfD7KjAFkFtQ==
+ dependencies:
+ "@atproto/common-web" "^0.2.3"
+ "@atproto/syntax" "^0.2.0"
+ iso-datestring-validator "^2.2.2"
+ multiformats "^9.9.0"
+ zod "^3.21.4"
+
"@atproto/ozone@^0.0.7":
version "0.0.7"
resolved "https://registry.yarnpkg.com/@atproto/ozone/-/ozone-0.0.7.tgz#bfad82bc1d0900e79401a82f13581f707415505a"
@@ -326,6 +351,13 @@
dependencies:
"@atproto/common-web" "^0.2.3"
+"@atproto/syntax@^0.2.0":
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.2.0.tgz#4bab724c02e11f8943b8ec101251082cf55067e9"
+ integrity sha512-K+9jl6mtxC9ytlR7msSiP9jVNqtdxEBSt0kOfsC924lqGwuD8nlUAMi1GSMgAZJGg/Rd+0MKXh789heTdeL3HQ==
+ dependencies:
+ "@atproto/common-web" "^0.2.3"
+
"@atproto/xrpc-server@^0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@atproto/xrpc-server/-/xrpc-server-0.4.2.tgz#23efd89086b85933f1b0cc00c86e895adcaac315"
@@ -351,6 +383,14 @@
"@atproto/lexicon" "^0.3.1"
zod "^3.21.4"
+"@atproto/xrpc@^0.4.2":
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.4.2.tgz#57812e0624be597b85f21471acf336513f35ccda"
+ integrity sha512-x4x2QB4nWmLjIpz2Ue9n/QVbVyJkk6tQMhvmDQaVFF89E3FcVI4rxF4uhzSxaLpbNtyVQBNEEmNHOr5EJLeHVA==
+ dependencies:
+ "@atproto/lexicon" "^0.3.2"
+ zod "^3.21.4"
+
"@aws-crypto/crc32@3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa"
@@ -3075,6 +3115,27 @@
xcode "^3.0.1"
xml2js "0.6.0"
+"@expo/config-plugins@~5.0.3":
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-5.0.4.tgz#216fea6558fe66615af1370de55193f4181cb23e"
+ integrity sha512-vzUcVpqOMs3h+hyRdhGwk+eGIOhXa5xYdd92yO17RMNHav3v/+ekMbs7XA2c3lepMO8Yd4/5hqmRw9ZTL6jGzg==
+ dependencies:
+ "@expo/config-types" "^47.0.0"
+ "@expo/json-file" "8.2.36"
+ "@expo/plist" "0.0.18"
+ "@expo/sdk-runtime-versions" "^1.0.0"
+ "@react-native/normalize-color" "^2.0.0"
+ chalk "^4.1.2"
+ debug "^4.3.1"
+ find-up "~5.0.0"
+ getenv "^1.0.0"
+ glob "7.1.6"
+ resolve-from "^5.0.0"
+ semver "^7.3.5"
+ slash "^3.0.0"
+ xcode "^3.0.1"
+ xml2js "0.4.23"
+
"@expo/config-plugins@~7.8.2":
version "7.8.2"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.8.2.tgz#c00ce93c4d6c2cb9e345ed9cd56ceeea05ab8ddb"
@@ -3098,6 +3159,11 @@
xcode "^3.0.1"
xml2js "0.6.0"
+"@expo/config-types@^47.0.0":
+ version "47.0.0"
+ resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-47.0.0.tgz#99eeabe0bba7a776e0f252b78beb0c574692c38d"
+ integrity sha512-r0pWfuhkv7KIcXMUiNACJmJKKwlTBGMw9VZHNdppS8/0Nve8HZMTkNRFQzTHW1uH3pBj8jEXpyw/2vSWDHex9g==
+
"@expo/config-types@^50.0.0", "@expo/config-types@^50.0.0-alpha.1":
version "50.0.0"
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-50.0.0.tgz#b534d3ec997ec60f8af24f6ad56244c8afc71a0b"
@@ -3120,6 +3186,23 @@
slugify "^1.3.4"
sucrase "^3.20.0"
+"@expo/config@~7.0.0":
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/@expo/config/-/config-7.0.3.tgz#c9c634e76186de25e296485e51418f1e52966e6e"
+ integrity sha512-joVtB5o+NF40Tmsdp65UzryRtbnCuMbXkVO4wJnNJO4aaK0EYLdHCYSewORVqNcDfGN0LphQr8VTG2npbd9CJA==
+ dependencies:
+ "@babel/code-frame" "~7.10.4"
+ "@expo/config-plugins" "~5.0.3"
+ "@expo/config-types" "^47.0.0"
+ "@expo/json-file" "8.2.36"
+ getenv "^1.0.0"
+ glob "7.1.6"
+ require-from-string "^2.0.2"
+ resolve-from "^5.0.0"
+ semver "7.3.2"
+ slugify "^1.3.4"
+ sucrase "^3.20.0"
+
"@expo/config@~8.5.0":
version "8.5.0"
resolved "https://registry.yarnpkg.com/@expo/config/-/config-8.5.0.tgz#c618e016c3272335e33fec02fb7fd67e4dcc3342"
@@ -3219,6 +3302,15 @@
semver "7.3.2"
tempy "0.3.0"
+"@expo/json-file@8.2.36":
+ version "8.2.36"
+ resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.36.tgz#62a505cb7f30a34d097386476794680a3f7385ff"
+ integrity sha512-tOZfTiIFA5KmMpdW9KF7bc6CFiGjb0xnbieJhTGlHrLL+ps2G0OkqmuZ3pFEXBOMnJYUVpnSy++52LFxvpa5ZQ==
+ dependencies:
+ "@babel/code-frame" "~7.10.4"
+ json5 "^1.0.1"
+ write-file-atomic "^2.3.0"
+
"@expo/json-file@^8.2.37":
version "8.2.37"
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.37.tgz#9c02d3b42134907c69cc0a027b18671b69344049"
@@ -3288,6 +3380,15 @@
split "^1.0.1"
sudo-prompt "9.1.1"
+"@expo/plist@0.0.18":
+ version "0.0.18"
+ resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.18.tgz#9abcde78df703a88f6d9fa1a557ee2f045d178b0"
+ integrity sha512-+48gRqUiz65R21CZ/IXa7RNBXgAI/uPSdvJqoN9x1hfL44DNbUoWHgHiEXTx7XelcATpDwNTz6sHLfy0iNqf+w==
+ dependencies:
+ "@xmldom/xmldom" "~0.7.0"
+ base64-js "^1.2.3"
+ xmlbuilder "^14.0.0"
+
"@expo/plist@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.1.0.tgz#eabc95f951d14e10c87fd0443ee01d567371f058"
@@ -4427,6 +4528,18 @@
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-escape-keydown" "1.0.3"
+"@radix-ui/react-dismissable-layer@1.0.5":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4"
+ integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-escape-keydown" "1.0.3"
+
"@radix-ui/react-dropdown-menu@^2.0.1":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.5.tgz#19bf4de8ffa348b4eb6a86842f14eff93d741170"
@@ -4441,6 +4554,20 @@
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-controllable-state" "1.0.1"
+"@radix-ui/react-dropdown-menu@^2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz#cdf13c956c5e263afe4e5f3587b3071a25755b63"
+ integrity sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-menu" "2.0.6"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
"@radix-ui/react-focus-guards@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad"
@@ -4458,6 +4585,16 @@
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-callback-ref" "1.0.1"
+"@radix-ui/react-focus-scope@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525"
+ integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
"@radix-ui/react-id@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0"
@@ -4491,6 +4628,31 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
+"@radix-ui/react-menu@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.6.tgz#2c9e093c1a5d5daa87304b2a2f884e32288ae79e"
+ integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-dismissable-layer" "1.0.5"
+ "@radix-ui/react-focus-guards" "1.0.1"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-popper" "1.1.3"
+ "@radix-ui/react-portal" "1.0.4"
+ "@radix-ui/react-presence" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-slot" "1.0.2"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ aria-hidden "^1.1.1"
+ react-remove-scroll "2.5.5"
+
"@radix-ui/react-popper@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.2.tgz#4c0b96fcd188dc1f334e02dba2d538973ad842e9"
@@ -4508,6 +4670,23 @@
"@radix-ui/react-use-size" "1.0.1"
"@radix-ui/rect" "1.0.1"
+"@radix-ui/react-popper@1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42"
+ integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@floating-ui/react-dom" "^2.0.0"
+ "@radix-ui/react-arrow" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+ "@radix-ui/react-use-rect" "1.0.1"
+ "@radix-ui/react-use-size" "1.0.1"
+ "@radix-ui/rect" "1.0.1"
+
"@radix-ui/react-portal@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.3.tgz#ffb961244c8ed1b46f039e6c215a6c4d9989bda1"
@@ -4516,6 +4695,14 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.3"
+"@radix-ui/react-portal@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15"
+ integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
"@radix-ui/react-presence@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
@@ -4624,6 +4811,13 @@
dependencies:
merge-options "^3.0.4"
+"@react-native-async-storage/async-storage@^1.15.2":
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.22.0.tgz#202a9afd15a5b829c39b709d0ca3942612441efc"
+ integrity sha512-b5KD010iiZnot86RbAaHpLuHwmPW2qA3SSN/OSZhd1kBoINEQEVBuv+uFtcaTxAhX27bT0wd13GOb2IOSDUXSA==
+ dependencies:
+ merge-options "^3.0.4"
+
"@react-native-camera-roll/camera-roll@^5.2.2":
version "5.7.2"
resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-5.7.2.tgz#db11525ae26c8a61630c424aebd323a7c784a921"
@@ -4792,13 +4986,6 @@
prompts "^2.4.2"
semver "^7.5.2"
-"@react-native-community/datetimepicker@7.6.1":
- version "7.6.1"
- resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-7.6.1.tgz#98bdee01e3df490526ee1125e438c2030becac1f"
- integrity sha512-g66Q2Kd9Uw3eRL7kkrTsGhi+eXxNoPDRFYH6z78sZQuYjPkUQgJDDMUYgBmaBsQx/fKMtemPrCj1ulGmyi0OSw==
- dependencies:
- invariant "^2.2.4"
-
"@react-native-community/eslint-config@^3.0.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@react-native-community/eslint-config/-/eslint-config-3.2.0.tgz#42f677d5fff385bccf1be1d3b8faa8c086cf998d"
@@ -8024,7 +8211,7 @@
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
-"@xmldom/xmldom@~0.7.7":
+"@xmldom/xmldom@~0.7.0", "@xmldom/xmldom@~0.7.7":
version "0.7.13"
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.13.tgz#ff34942667a4e19a9f4a0996a76814daac364cf3"
integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==
@@ -11637,6 +11824,14 @@ expo-camera@~14.0.1:
dependencies:
invariant "^2.2.4"
+expo-constants@^13.0.2:
+ version "13.2.4"
+ resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-13.2.4.tgz#eab4a553f074b2c60ad7a158d3b82e3484a94606"
+ integrity sha512-Zobau8EuTk2GgafwkfGnWM6CmSLB7X8qnQXVuXe0nd3v92hfQUmRWGhJwH88uxXj3LrfqctM6PaJ8taG1vxfBw==
+ dependencies:
+ "@expo/config" "~7.0.0"
+ uuid "^3.3.2"
+
expo-constants@~15.4.0:
version "15.4.1"
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-15.4.1.tgz#f76f347cf687b6630e1e3b9a385a4e42771671a4"
@@ -11686,6 +11881,13 @@ expo-dev-menu@4.5.3:
expo-dev-menu-interface "1.7.2"
semver "^7.5.3"
+expo-device@~4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/expo-device/-/expo-device-4.1.1.tgz#5de94144113ffb7fa0f37fa3d70e452113954c10"
+ integrity sha512-It0SGtKcvzQSf+Co6zdPdB63zZvG2/rDolB1lqswMNKj03Y7KVU41s5tcQCqNczj7tmeN3CJy7A8YhYGKdb7gA==
+ dependencies:
+ ua-parser-js "^0.7.19"
+
expo-device@~5.9.2:
version "5.9.2"
resolved "https://registry.yarnpkg.com/expo-device/-/expo-device-5.9.2.tgz#697e96f52d213a141b6f265f1e274e9d5e98c92c"
@@ -11751,6 +11953,14 @@ expo-keep-awake@~12.8.1:
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-12.8.1.tgz#3c8df9d86c265741b5e7bdd36965aa0c6fc17df0"
integrity sha512-P/VZFV02Rzgj13skMwH+ceGOGZSEdaUu5n7pCS3wThh2LppZjPJ7sBxUwyzeLa3DXEVUtwLZi+BiQ91wPwy9Gg==
+expo-linking@^6.2.2:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-6.2.2.tgz#b7e148068ae49fd9ad814428c16fdf7a236e8aca"
+ integrity sha512-FEe6lP4f7xFT/vjoHRG+tt6EPVtkEGaWNK1smpaUevmNdyCJKqW0PDB8o8sfG6y7fly8ULe8qg3HhKh5J7aqUQ==
+ dependencies:
+ expo-constants "~15.4.3"
+ invariant "^2.2.4"
+
expo-localization@~14.8.2:
version "14.8.2"
resolved "https://registry.yarnpkg.com/expo-localization/-/expo-localization-14.8.2.tgz#e0bbed2293265834d21a1c58d3a5f8d265bd04ae"
@@ -14870,6 +15080,16 @@ js-queue@2.0.2:
dependencies:
easy-stack "^1.0.1"
+js-sha256@^0.10.1:
+ version "0.10.1"
+ resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.10.1.tgz#b40104ba1368e823fdd5f41b66b104b15a0da60d"
+ integrity sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==
+
+js-sha256@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.11.0.tgz#256a921d9292f7fe98905face82e367abaca9576"
+ integrity sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==
+
js-sha256@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
@@ -15054,7 +15274,7 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
-json5@^1.0.2:
+json5@^1.0.1, json5@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
@@ -18350,11 +18570,23 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
+react-keyed-flatten-children@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/react-keyed-flatten-children/-/react-keyed-flatten-children-3.0.0.tgz#b6ad0bde437d3ab86c8af3a1902d164be2a29d67"
+ integrity sha512-tSH6gvOyQjt3qtjG+kU9sTypclL1672yjpVufcE3aHNM0FhvjBUQZqsb/awIux4zEuVC3k/DP4p0GdTT/QUt/Q==
+ dependencies:
+ react-is "^18.2.0"
+
react-native-appstate-hook@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/react-native-appstate-hook/-/react-native-appstate-hook-1.0.6.tgz#cbc16e7b89cfaea034cabd999f00e99053cabd06"
integrity sha512-0hPVyf5yLxCSVrrNEuGqN1ZnSSj3Ye2gZex0NtcK/AHYwMc0rXWFNZjBKOoZSouspqu3hXBbQ6NOUSTzrME1AQ==
+react-native-date-picker@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/react-native-date-picker/-/react-native-date-picker-4.4.0.tgz#fe5b6eb8d85a4a30b2991ada5169a30ce5023ead"
+ integrity sha512-Axx3byihwwhKRLRVjPAr/UaEysapkRcKmjjM8/05UaVm4Q0xDn2RFUcRdy1QAahhRcjLjlVYhepxvU5bdgy7ZQ==
+
react-native-dotenv@^3.3.1:
version "3.4.9"
resolved "https://registry.yarnpkg.com/react-native-dotenv/-/react-native-dotenv-3.4.9.tgz#621c5b0c1d0c5c7f569bfe5a1d804bec7885c010"
@@ -18388,6 +18620,13 @@ react-native-gesture-handler@~2.14.0:
lodash "^4.17.21"
prop-types "^15.7.2"
+react-native-get-random-values@^1.6.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.10.0.tgz#c2c5f12a4ef8b1175145347b4a4b9f9a40d9ffc8"
+ integrity sha512-gZ1zbXhbb8+Jy9qYTV8c4Nf45/VB4g1jmXuavY5rPfUn7x3ok9Vl3FTl0dnE92Z4FFtfbUNNwtSfcmomdtWg+A==
+ dependencies:
+ fast-base64-decode "^1.0.0"
+
react-native-get-random-values@~1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.8.0.tgz#1cb4bd4bd3966a356e59697b8f372999fe97cb16"
@@ -19861,6 +20100,49 @@ standard-as-callback@^2.1.0:
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==
+statsig-js@4.45.1:
+ version "4.45.1"
+ resolved "https://registry.yarnpkg.com/statsig-js/-/statsig-js-4.45.1.tgz#b1f5b9c52adc4a8aece376fb011416c89227932f"
+ integrity sha512-h94RzFQsJCQCNwQXpZ9OBXcvCxDnkXF6OrCekd81ySvY2l4JSowpxMWX3Iw6IDFzfTfKdER9JQzFLhMSQbT+YQ==
+ dependencies:
+ js-sha256 "^0.10.1"
+ uuid "^8.3.2"
+
+statsig-js@4.49.0:
+ version "4.49.0"
+ resolved "https://registry.yarnpkg.com/statsig-js/-/statsig-js-4.49.0.tgz#8470a9ac218a93d36f4b7b306ff9377e48064740"
+ integrity sha512-N4drx6fzI168Q4NndFY3IJbSDqpWSBWvS290H/RnT/g3Et58SvtXzG5qqgzmqy4CwcmwH+IL8K15pL7hPnfvUQ==
+ dependencies:
+ js-sha256 "^0.11.0"
+ uuid "^8.3.2"
+
+statsig-react-native-expo@^4.6.1:
+ version "4.6.1"
+ resolved "https://registry.yarnpkg.com/statsig-react-native-expo/-/statsig-react-native-expo-4.6.1.tgz#0bdf49fee7112f7f28bff2405f4ba0c1727bb3d6"
+ integrity sha512-rB60c+WSrQPmjW9j75d+acUtwSOe38PE2KTDHiOv1Mf+0TCcFtGYlJmKCibWvbeXR7ZAyjjGeroh23bCSEZauQ==
+ dependencies:
+ "@react-native-async-storage/async-storage" "^1.15.2"
+ expo-constants "^13.0.2"
+ expo-device "~4.1.1"
+ js-sha256 "^0.9.0"
+ react-native-get-random-values "^1.6.0"
+ statsig-react "^1.21.1"
+ uuid "^8.3.2"
+
+statsig-react@^1.21.1:
+ version "1.35.0"
+ resolved "https://registry.yarnpkg.com/statsig-react/-/statsig-react-1.35.0.tgz#ad5730b83f564c640623e954fcbcbe848e939946"
+ integrity sha512-KLN7dhq6FvAl25Z0QN6IINFBgM3yn0GMafoE698tYZqRf911xvevFaR7qUXiTz3W9vmFYrmFRouqVMfCv7DW0A==
+ dependencies:
+ statsig-js "4.45.1"
+
+statsig-react@^1.36.0:
+ version "1.36.0"
+ resolved "https://registry.yarnpkg.com/statsig-react/-/statsig-react-1.36.0.tgz#c2171268a6c76eee534849ec9556b836baba04b6"
+ integrity sha512-QcTHla3ypfn2RvrnHGNlqWbiC2W/ZjcMM5LT6ExNV4skH7Xhspto3dMS3JVzBhOb74OEDZK4DbxQj9Wdz6XW0w==
+ dependencies:
+ statsig-js "4.49.0"
+
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
@@ -20805,6 +21087,11 @@ typescript@^5.3.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
+ua-parser-js@^0.7.19:
+ version "0.7.37"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832"
+ integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==
+
ua-parser-js@^0.7.33:
version "0.7.35"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.35.tgz#8bda4827be4f0b1dda91699a29499575a1f1d307"
@@ -21086,7 +21373,7 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
-uuid@^3.0.1:
+uuid@^3.0.1, uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
@@ -21838,6 +22125,14 @@ xml-name-validator@^4.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
+xml2js@0.4.23:
+ version "0.4.23"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
+ integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
xml2js@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.0.tgz#07afc447a97d2bd6507a1f76eeadddb09f7a8282"