Show pinned tweets in the web UI

This commit is contained in:
Alessio 2024-03-18 21:30:01 -07:00
parent ca7cf613f9
commit 41e525d223
7 changed files with 46 additions and 12 deletions

View File

@ -1,10 +1,11 @@
#define NAME "Offline Twitter" #define NAME "Offline Twitter"
#define EXE_NAME "twitter.exe" #define EXE_NAME "twitter.exe"
; The `version` macro should be passed from command line using `/Dversion=[...]`
[Setup] [Setup]
AppName={#NAME} AppName={#NAME}
AppVersion={#VERSION} AppVersion={#version}
WizardStyle=modern WizardStyle=modern
DefaultDirName={autopf}/offline-twitter DefaultDirName={autopf}/offline-twitter
DefaultGroupName={#NAME} DefaultGroupName={#NAME}

View File

@ -91,7 +91,8 @@ func (app *Application) UserFeed(w http.ResponseWriter, r *http.Request) {
data := struct { data := struct {
persistence.Feed persistence.Feed
scraper.UserID scraper.UserID
FeedType string PinnedTweet scraper.Tweet
FeedType string
}{Feed: feed, UserID: user.ID} }{Feed: feed, UserID: user.ID}
if len(parts) == 2 { if len(parts) == 2 {
@ -100,6 +101,16 @@ func (app *Application) UserFeed(w http.ResponseWriter, r *http.Request) {
data.FeedType = "" data.FeedType = ""
} }
// Add a pinned tweet if there is one and it's in the DB; otherwise skip
if user.PinnedTweetID != scraper.TweetID(0) && len(parts) <= 1 || parts[1] == "without_replies" {
data.PinnedTweet, err = app.Profile.GetTweetById(user.PinnedTweetID)
if err == nil {
feed.TweetTrove.Tweets[data.PinnedTweet.ID] = data.PinnedTweet
} else if !errors.Is(err, persistence.ErrNotInDB) {
panic(err)
}
}
if r.Header.Get("HX-Request") == "true" && c.CursorPosition == persistence.CURSOR_MIDDLE { if r.Header.Get("HX-Request") == "true" && c.CursorPosition == persistence.CURSOR_MIDDLE {
// It's a Show More request // It's a Show More request
app.buffered_render_htmx(w, "timeline", PageGlobalData{TweetTrove: feed.TweetTrove}, data) app.buffered_render_htmx(w, "timeline", PageGlobalData{TweetTrove: feed.TweetTrove}, data)

View File

@ -81,10 +81,9 @@ func TestUserFeed(t *testing.T) {
title_node := cascadia.Query(root, selector("title")) title_node := cascadia.Query(root, selector("title"))
assert.Equal(title_node.FirstChild.Data, "@Cernovich | Offline Twitter") assert.Equal(title_node.FirstChild.Data, "@Cernovich | Offline Twitter")
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet")) assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 8)
assert.Len(tweet_nodes, 7) assert.Len(cascadia.QueryAll(root, selector(".timeline > .pinned-tweet")), 1)
including_quote_tweets := cascadia.QueryAll(root, selector(".tweet")) assert.Len(cascadia.QueryAll(root, selector(".tweet")), 12) // Pinned tweet appears again
assert.Len(including_quote_tweets, 10)
} }
func TestUserFeedWithEntityInBio(t *testing.T) { func TestUserFeedWithEntityInBio(t *testing.T) {
@ -224,7 +223,7 @@ func TestTimeline(t *testing.T) {
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter") assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet")) tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
assert.Len(tweet_nodes, 18) assert.Len(tweet_nodes, 19)
} }
func TestTimelineWithCursor(t *testing.T) { func TestTimelineWithCursor(t *testing.T) {

View File

@ -343,6 +343,18 @@ h3 {
color: var(--color-twitter-blue); color: var(--color-twitter-blue);
} }
.pinned-tweet__pin-container {
margin: 0.5em 0em -1em 3em;
z-index: 1;
position: relative; /* z-index is ignored if `position` is "static" */
gap: 0.2em;
}
img.svg-icon.pinned-tweet__pin-icon {
filter: invert(43%) saturate(30%);
width: 1em;
height: auto;
}
.row { .row {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -474,7 +486,7 @@ ul.quick-links {
padding-top: 0.8em; padding-top: 0.8em;
padding-bottom: 0.8em; padding-bottom: 0.8em;
} }
.timeline > .tweet { .timeline > .tweet, .timeline > .pinned-tweet {
/* not for nested (i.e., quoted) tweets */ /* not for nested (i.e., quoted) tweets */
border-bottom: 1px solid var(--color-twitter-off-white-dark); border-bottom: 1px solid var(--color-twitter-off-white-dark);
} }

View File

@ -22,6 +22,15 @@
</div> </div>
<div class="timeline user-feed-timeline"> <div class="timeline user-feed-timeline">
{{if .PinnedTweet.ID}}
<div class="pinned-tweet">
<div class="row pinned-tweet__pin-container">
<img class="svg-icon pinned-tweet__pin-icon" src="/static/icons/pin.svg" width="24" height="24" />
<span>Pinned</span>
</div>
{{template "tweet" (dict "TweetID" .PinnedTweet.ID "RetweetID" 0)}}
</div>
{{end}}
{{template "timeline" .}} {{template "timeline" .}}
</div> </div>
{{end}} {{end}}

View File

@ -207,10 +207,11 @@ func TestSearchDateFilters(t *testing.T) {
c.UntilTimestamp.Time = time.Date(2021, 10, 1, 0, 0, 0, 0, time.UTC) c.UntilTimestamp.Time = time.Date(2021, 10, 1, 0, 0, 0, 0, time.UTC)
feed, err = profile.NextPage(c, UserID(0)) feed, err = profile.NextPage(c, UserID(0))
require.NoError(err) require.NoError(err)
assert.Len(feed.Items, 3) assert.Len(feed.Items, 4)
assert.Equal(feed.Items[0].TweetID, TweetID(1439027915404939265)) assert.Equal(feed.Items[0].TweetID, TweetID(1439747634277740546))
assert.Equal(feed.Items[1].TweetID, TweetID(1439068749336748043)) assert.Equal(feed.Items[1].TweetID, TweetID(1439027915404939265))
assert.Equal(feed.Items[2].TweetID, TweetID(1439067163508150272)) assert.Equal(feed.Items[2].TweetID, TweetID(1439068749336748043))
assert.Equal(feed.Items[3].TweetID, TweetID(1439067163508150272))
} }
func TestSearchMediaFilters(t *testing.T) { func TestSearchMediaFilters(t *testing.T) {

View File

@ -175,6 +175,7 @@ INSERT INTO tweets VALUES
(2857357,1489944024278523906,96906231,'According to @gofundme it was "as a result of multiple discussions with locals law enforcement and *police reports of violence and other unlawful activity*". ABSOLUTE LIES! I asked police officers live and they CONFIRMED there was no violence. Pure censorship. #BankruptGoFundMe',1644065311000,5753,2127,219,110,0,0,'gofundme','','BankruptGoFundMe',NULL,NULL,0,1,0,0,0), (2857357,1489944024278523906,96906231,'According to @gofundme it was "as a result of multiple discussions with locals law enforcement and *police reports of violence and other unlawful activity*". ABSOLUTE LIES! I asked police officers live and they CONFIRMED there was no violence. Pure censorship. #BankruptGoFundMe',1644065311000,5753,2127,219,110,0,0,'gofundme','','BankruptGoFundMe',NULL,NULL,0,1,0,0,0),
(121936,1513313535480287235,1178839081222115328,'Smh wish I could RT',1649637037000,4,0,1,0,1513312559981551619,0,'PublicAnthony','PublicAnthony','',NULL,NULL,0,1,0,0,0), (121936,1513313535480287235,1178839081222115328,'Smh wish I could RT',1649637037000,4,0,1,0,1513312559981551619,0,'PublicAnthony','PublicAnthony','',NULL,NULL,0,1,0,0,0),
(869468,1624833173514293249,1240784920831762433,'',1676225391000,1,0,0,0,0,0,'','','','1OwGWwnoleRGQ',NULL,0,1,0,0,0), (869468,1624833173514293249,1240784920831762433,'',1676225391000,1,0,0,0,0,0,'','','','1OwGWwnoleRGQ',NULL,0,1,0,0,0),
(2090918,1439747634277740546,358545917,'Explain why staff but not talent at these events have to wear masks. Using science.',1632097559000,29832,4145,783,163,0,0,'','','',NULL,NULL,0,1,1,1710818767264,0),
(2857431,1695110851324256692,19370504,replace('My dad was a doctor, he retired this past year \n\nHes been healthy his whole life, and he saw the titanic shift (no pun intended) in obesity being normalized in real time \n\nIt used to be a 300lb person was uncommon \n\nThen it was 400lbs\n\nThen 500lbs\n\nHospitals had to upgrade their scales to veterinary scales they use in zoos,\nThats how fat people became \n\nObese patients would be OFFENDED if you suggested they lose weight \n\nThey would complain if you told them their back pain was because their BMI was 45 \n\nTheyd ignore all suggestions of exercise or diet and complain why cant they just take a pill \n\nThis wasnt outliers, this is at least 50% of the population \n\nUntil you work with general public, you cannot fully conceive the existent of peoples sloth and apathy towards their own quality of life','\n',char(10)),1692980895000,1894,224,137,25,0,0,'','','',NULL,NULL,0,1,1,1693055764000,1), (2857431,1695110851324256692,19370504,replace('My dad was a doctor, he retired this past year \n\nHes been healthy his whole life, and he saw the titanic shift (no pun intended) in obesity being normalized in real time \n\nIt used to be a 300lb person was uncommon \n\nThen it was 400lbs\n\nThen 500lbs\n\nHospitals had to upgrade their scales to veterinary scales they use in zoos,\nThats how fat people became \n\nObese patients would be OFFENDED if you suggested they lose weight \n\nThey would complain if you told them their back pain was because their BMI was 45 \n\nTheyd ignore all suggestions of exercise or diet and complain why cant they just take a pill \n\nThis wasnt outliers, this is at least 50% of the population \n\nUntil you work with general public, you cannot fully conceive the existent of peoples sloth and apathy towards their own quality of life','\n',char(10)),1692980895000,1894,224,137,25,0,0,'','','',NULL,NULL,0,1,1,1693055764000,1),
(1405789,1698426460061487546,1458284524761075714,'Zig''s "comptime" leads to the most elegant reflection code I''ve ever seen. It''s much cleaner and more expressive than, e.g., Python''s various __methods__, or worse, the deranged "metaclasses" nonsense; but it also has no runtime cost!',1693771397000,6,0,1,1,0,1692962678824648811,'','','',NULL,NULL,0,1,0,0,0), (1405789,1698426460061487546,1458284524761075714,'Zig''s "comptime" leads to the most elegant reflection code I''ve ever seen. It''s much cleaner and more expressive than, e.g., Python''s various __methods__, or worse, the deranged "metaclasses" nonsense; but it also has no runtime cost!',1693771397000,6,0,1,1,0,1692962678824648811,'','','',NULL,NULL,0,1,0,0,0),
(1408662,1698762403163304110,1458284524761075714,replace('Another very cool use of Zig''s "comptime" is it lets you write real, compiled mini-languages in strings; e.g.:\n\n- SQL prepared statements\n- "printf" style format strings\n- regexps\n\nEvery language uses these, but they''re interpreted at runtime, even in compiled languages.','\n',char(10)),1693851493000,7,2,3,0,0,1698426460061487546,'','','',NULL,NULL,0,1,0,0,0), (1408662,1698762403163304110,1458284524761075714,replace('Another very cool use of Zig''s "comptime" is it lets you write real, compiled mini-languages in strings; e.g.:\n\n- SQL prepared statements\n- "printf" style format strings\n- regexps\n\nEvery language uses these, but they''re interpreted at runtime, even in compiled languages.','\n',char(10)),1693851493000,7,2,3,0,0,1698426460061487546,'','','',NULL,NULL,0,1,0,0,0),