diff --git a/internal/webserver/handler_search.go b/internal/webserver/handler_search.go
index a46a8b2..9547449 100644
--- a/internal/webserver/handler_search.go
+++ b/internal/webserver/handler_search.go
@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "strconv"
"strings"
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
@@ -29,6 +30,25 @@ func (app *Application) Search(w http.ResponseWriter, r *http.Request) {
// Handle "@username"
if search_text[0] == '@' {
http.Redirect(w, r, fmt.Sprintf("/%s", search_text[1:]), 302)
+ return
+ }
+
+ // Handle pasted URLs
+ maybe_url, err := url.Parse(search_text)
+ if err == nil && (maybe_url.Host == "twitter.com" || maybe_url.Host == "mobile.twitter.com") {
+ parts := strings.Split(strings.Trim(maybe_url.Path, "/"), "/")
+ if len(parts) == 3 && parts[1] == "status" {
+ id, err := strconv.Atoi(parts[2])
+ if err == nil {
+ http.Redirect(w, r, fmt.Sprintf("/tweet/%d", id), 302)
+ return
+ }
+ }
+
+ if len(parts) == 1 {
+ http.Redirect(w, r, fmt.Sprintf("/%s", parts[0]), 302)
+ return
+ }
}
c, err := persistence.NewCursorFromSearchQuery(search_text)
diff --git a/internal/webserver/server_test.go b/internal/webserver/server_test.go
index 95651bc..8c3af3f 100644
--- a/internal/webserver/server_test.go
+++ b/internal/webserver/server_test.go
@@ -216,6 +216,38 @@ func TestSearchRedirectOnUserHandle(t *testing.T) {
assert.Equal(resp.Header.Get("Location"), "/somebody")
}
+func TestSearchRedirectOnTweetLink(t *testing.T) {
+ assert := assert.New(t)
+
+ // Desktop URL
+ resp := do_request(httptest.NewRequest("GET",
+ fmt.Sprintf("/search/%s", url.PathEscape("https://twitter.com/wispem_wantex/status/1695221528617468324")),
+ nil))
+ assert.Equal(resp.StatusCode, 302)
+ assert.Equal(resp.Header.Get("Location"), "/tweet/1695221528617468324")
+
+ // Mobile URL
+ resp = do_request(httptest.NewRequest("GET",
+ fmt.Sprintf("/search/%s", url.PathEscape("https://mobile.twitter.com/wispem_wantex/status/1695221528617468324")),
+ nil))
+ assert.Equal(resp.StatusCode, 302)
+ assert.Equal(resp.Header.Get("Location"), "/tweet/1695221528617468324")
+}
+
+func TestSearchRedirectOnUserFeedLink(t *testing.T) {
+ assert := assert.New(t)
+
+ // Desktop URL
+ resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://twitter.com/agsdf")), nil))
+ assert.Equal(resp.StatusCode, 302)
+ assert.Equal(resp.Header.Get("Location"), "/agsdf")
+
+ // Mobile URL
+ resp = do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://mobile.twitter.com/agsdfhh")), nil))
+ assert.Equal(resp.StatusCode, 302)
+ assert.Equal(resp.Header.Get("Location"), "/agsdfhh")
+}
+
// Tweet Detail page
// -----------------
diff --git a/internal/webserver/static/styles.css b/internal/webserver/static/styles.css
index 05f77ee..14762ad 100644
--- a/internal/webserver/static/styles.css
+++ b/internal/webserver/static/styles.css
@@ -243,6 +243,7 @@ h3 {
.posted-at-container {
flex-grow: 1;
+ min-width: 5em;
}
p.posted-at {
float: right;
@@ -550,6 +551,7 @@ ul.dropdown-items {
outline: 1px solid var(--color-outline-gray);
border-radius: 0.3em;
visibility: hidden;
+ z-index: 1; /* otherwise in quote-tweets, the dropdown button from quoting-tweet is on top of it */
}
.dropdown-button:focus + .dropdown-items, .dropdown-items:hover {
visibility: visible;
diff --git a/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl b/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl
index f69641b..d3c6e19 100644
--- a/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl
+++ b/internal/webserver/tpl/tweet_page_includes/single_tweet.tpl
@@ -69,7 +69,9 @@
class="embedded-link rounded-gray-outline unstyled-link"
target="_blank"
href="{{.Text}}"
- style="max-width: {{if (ne .ThumbnailWidth 0)}}{{.ThumbnailWidth}}px {{else}}fit-content {{end}}">
+ style="max-width: {{if (ne .ThumbnailWidth 0)}}{{.ThumbnailWidth}}px {{else}}fit-content {{end}}"
+ hx-trigger="click consume"
+ >