Show pinned tweets in the web UI
This commit is contained in:
parent
ca7cf613f9
commit
41e525d223
@ -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}
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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}}
|
||||||
|
@ -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) {
|
||||||
|
@ -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\nHe’s 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,\nThat’s 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\nThey’d ignore all suggestions of exercise or diet and complain why can’t they just take a pill \n\nThis wasn’t outliers, this is at least 50% of the population \n\nUntil you work with general public, you cannot fully conceive the existent of people’s 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\nHe’s 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,\nThat’s 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\nThey’d ignore all suggestions of exercise or diet and complain why can’t they just take a pill \n\nThis wasn’t outliers, this is at least 50% of the population \n\nUntil you work with general public, you cannot fully conceive the existent of people’s 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),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user