mirror of
https://github.com/tanrax/org-social.el
synced 2026-01-09 14:23:33 +01:00
538 lines
23 KiB
EmacsLisp
538 lines
23 KiB
EmacsLisp
;;; org-social-ui-timeline.el --- Timeline buffer for Org-social -*- lexical-binding: t -*- -*- coding: utf-8 -*-
|
|
|
|
;; SPDX-License-Identifier: GPL-3.0
|
|
;; Author: Andros Fenollosa <hi@andros.dev>
|
|
;; Version: 2.0
|
|
;; URL: https://github.com/tanrax/org-social.el
|
|
|
|
;;; Commentary:
|
|
;; Timeline view with pagination and auto-refresh.
|
|
|
|
;;; Code:
|
|
|
|
(require 'org-social-variables)
|
|
(require 'org-social-ui-core)
|
|
(require 'org-social-ui-utils)
|
|
(require 'org-social-ui-components)
|
|
|
|
;; Forward declarations
|
|
(declare-function org-social-relay--get-timeline "org-social-relay" ())
|
|
(declare-function org-social-feed--get-timeline "org-social-feed" ())
|
|
(declare-function org-social-feed--process-queue "org-social-feed" ())
|
|
(declare-function org-social-relay--check-posts-for-replies "org-social-relay" (post-urls callback))
|
|
|
|
;; Refresh timer variable
|
|
(defvar org-social-ui--refresh-timer nil
|
|
"Timer for automatic timeline refresh.")
|
|
|
|
(defun org-social-ui--insert-timeline-header ()
|
|
"Insert timeline header with navigation and actions."
|
|
(org-social-ui--insert-logo)
|
|
|
|
;; Navigation buttons
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui-timeline))
|
|
:help-echo "View timeline"
|
|
" 📰 Timeline ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui-notifications))
|
|
:help-echo "View notifications"
|
|
" 🔔 Notifications ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui-groups))
|
|
:help-echo "View groups"
|
|
" 👥 Groups ")
|
|
|
|
(org-social-ui--insert-formatted-text "\n\n")
|
|
|
|
;; Action buttons
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-file--new-post))
|
|
:help-echo "Create a new post"
|
|
" ✍ New Post ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-file--new-poll))
|
|
:help-echo "Create a new poll"
|
|
" 📊 New Poll ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui--refresh))
|
|
:help-echo "Refresh timeline"
|
|
" ↻ Refresh ")
|
|
|
|
(org-social-ui--insert-formatted-text "\n\n")
|
|
|
|
;; Help text
|
|
(org-social-ui--insert-formatted-text "Navigation: (n) Next | (p) Previous | (t) Thread | (P) Profile\n" nil "#666666")
|
|
(org-social-ui--insert-formatted-text "Post: (c) New Post | (l) New Poll | (r) Reply | (R) React\n" nil "#666666")
|
|
(org-social-ui--insert-formatted-text "Actions: (N) Notifications | (G) Groups\n" nil "#666666")
|
|
(org-social-ui--insert-formatted-text "Other: (g) Refresh | (q) Quit\n" nil "#666666")
|
|
|
|
(org-social-ui--insert-separator))
|
|
|
|
(defun org-social-ui--insert-timeline-posts (timeline)
|
|
"Insert TIMELINE posts with infinite scroll pagination."
|
|
(when timeline
|
|
;; Store timeline globally for pagination
|
|
(setq org-social-ui--timeline-current-list timeline)
|
|
|
|
;; Calculate pagination
|
|
(let* ((total-posts (length timeline))
|
|
(posts-shown (* org-social-ui--current-page org-social-ui--posts-per-page)))
|
|
|
|
;; Insert posts for current page
|
|
(org-social-ui--insert-timeline-posts-paginated)
|
|
|
|
;; Insert "Show more" button if there are more posts
|
|
(when (< posts-shown total-posts)
|
|
(org-social-ui--insert-formatted-text "\n")
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui--timeline-next-page))
|
|
:help-echo "Load more posts"
|
|
" Show more ")
|
|
(org-social-ui--insert-formatted-text "\n")))))
|
|
|
|
(defun org-social-ui--insert-timeline-posts-paginated ()
|
|
"Insert the current page of timeline posts."
|
|
(when org-social-ui--timeline-current-list
|
|
(let* ((start-idx (* (- org-social-ui--current-page 1) org-social-ui--posts-per-page))
|
|
(end-idx (* org-social-ui--current-page org-social-ui--posts-per-page))
|
|
(posts-to-show (cl-subseq org-social-ui--timeline-current-list
|
|
start-idx
|
|
(min end-idx (length org-social-ui--timeline-current-list)))))
|
|
(dolist (post posts-to-show)
|
|
(org-social-ui--post-component post org-social-ui--timeline-current-list)))))
|
|
|
|
;;; Notifications Screen
|
|
|
|
(defun org-social-ui--insert-notifications-header ()
|
|
"Insert notifications header with navigation and actions."
|
|
(org-social-ui--insert-logo)
|
|
|
|
;; Navigation buttons
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui-timeline))
|
|
:help-echo "View timeline"
|
|
" 📰 Timeline ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui-notifications))
|
|
:help-echo "View notifications"
|
|
" 🔔 Notifications ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui-groups))
|
|
:help-echo "View groups"
|
|
" 👥 Groups ")
|
|
|
|
(org-social-ui--insert-formatted-text "\n\n")
|
|
|
|
;; Action buttons
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui--refresh))
|
|
:help-echo "Refresh notifications"
|
|
" ↻ Refresh ")
|
|
|
|
(org-social-ui--insert-formatted-text "\n\n")
|
|
|
|
;; Help text
|
|
(org-social-ui--insert-formatted-text "Your Mentions and Replies\n" 1.2 "#4a90e2")
|
|
(org-social-ui--insert-formatted-text "Navigation:\n" nil "#666666")
|
|
(org-social-ui--insert-formatted-text "(n) Next | (p) Previous | (T) Timeline | (G) Groups\n" nil "#666666")
|
|
(org-social-ui--insert-formatted-text "Other: (g) Refresh | (q) Quit\n" nil "#666666")
|
|
|
|
(org-social-ui--insert-separator))
|
|
|
|
(defun org-social-ui--mention-component (mention-url)
|
|
"Insert a mention component for MENTION-URL."
|
|
(org-social-ui--insert-formatted-text "📧 " 1.1 "#ff6600")
|
|
(org-social-ui--insert-formatted-text "New mention: ")
|
|
|
|
;; Extract info from URL (format: https://domain.com/social.org#timestamp)
|
|
(let ((author-url (when (string-match "\\(.*\\)#" mention-url)
|
|
(match-string 1 mention-url)))
|
|
(timestamp (when (string-match "#\\(.+\\)$" mention-url)
|
|
(match-string 1 mention-url))))
|
|
|
|
(when author-url
|
|
;; Author name button
|
|
(widget-create 'push-button
|
|
:notify `(lambda (&rest _)
|
|
(org-social-ui-profile ,author-url))
|
|
:help-echo (format "View profile: %s" author-url)
|
|
(format "@%s" (file-name-nondirectory (string-trim-right author-url "/social.org"))))
|
|
|
|
(org-social-ui--insert-formatted-text " • ")
|
|
|
|
(when timestamp
|
|
(org-social-ui--insert-formatted-text (org-social--format-date timestamp) nil "#666666")))
|
|
|
|
(org-social-ui--insert-formatted-text "\n ")
|
|
|
|
;; Action buttons
|
|
(widget-create 'push-button
|
|
:notify `(lambda (&rest _)
|
|
(org-social-ui-thread ,mention-url))
|
|
:help-echo "View thread"
|
|
" 🧵 View Thread ")
|
|
|
|
(org-social-ui--insert-formatted-text " ")
|
|
|
|
(when author-url
|
|
(widget-create 'push-button
|
|
:notify `(lambda (&rest _)
|
|
(org-social-file--new-post ,author-url ,timestamp))
|
|
:help-echo "Reply to mention"
|
|
" ↳ Reply "))
|
|
|
|
(org-social-ui--insert-formatted-text "\n")
|
|
(org-social-ui--insert-separator)))
|
|
|
|
(defun org-social-ui--insert-notifications-content (mentions)
|
|
"Insert notifications content with MENTIONS."
|
|
(if mentions
|
|
(progn
|
|
(org-social-ui--insert-formatted-text (format "Found %d mention%s:\n\n"
|
|
(length mentions)
|
|
(if (= (length mentions) 1) "" "s"))
|
|
nil "#4a90e2")
|
|
(dolist (mention mentions)
|
|
(org-social-ui--mention-component mention)))
|
|
(org-social-ui--insert-formatted-text "No new mentions or replies found.\n" nil "#666666")
|
|
(when (and (boundp 'org-social-relay) org-social-relay (not (string-empty-p org-social-relay)))
|
|
(org-social-ui--insert-formatted-text "Make sure your relay is properly configured.\n" nil "#666666"))
|
|
(org-social-ui--insert-formatted-text "\nYour public URL: " nil "#666666")
|
|
(org-social-ui--insert-formatted-text (or org-social-my-public-url "Not configured") nil "#4a90e2")))
|
|
|
|
;;; Main UI Functions
|
|
|
|
(defun org-social-ui-timeline ()
|
|
"Display timeline screen."
|
|
(interactive)
|
|
|
|
;; Validate required configuration
|
|
(unless (and (boundp 'org-social-file)
|
|
org-social-file
|
|
(not (string-empty-p org-social-file)))
|
|
(error "Org-social-file is not configured. Please set it in your configuration"))
|
|
|
|
(unless (and (boundp 'org-social-relay)
|
|
org-social-relay
|
|
(not (string-empty-p org-social-relay)))
|
|
(error "Org-social-relay is not configured. Please set it to a relay server URL (e.g., \"https://org-social-relay.andros.dev/\")"))
|
|
|
|
(unless (and (boundp 'org-social-my-public-url)
|
|
org-social-my-public-url
|
|
(not (string-empty-p org-social-my-public-url)))
|
|
(error "Org-social-my-public-url is not configured. Please set it to your public social.org URL"))
|
|
|
|
(setq org-social-ui--current-screen 'timeline)
|
|
(setq org-social-ui--current-page 1)
|
|
|
|
;; Clear replies cache on timeline refresh
|
|
(clrhash org-social-ui--replies-cache)
|
|
|
|
(let ((buffer-name org-social-ui--timeline-buffer-name))
|
|
(switch-to-buffer buffer-name)
|
|
(kill-all-local-variables)
|
|
|
|
;; Disable read-only mode before modifying buffer
|
|
(setq buffer-read-only nil)
|
|
|
|
(let ((inhibit-read-only t))
|
|
(erase-buffer))
|
|
(remove-overlays)
|
|
|
|
;; Insert header
|
|
(org-social-ui--insert-timeline-header)
|
|
|
|
;; Show loading message
|
|
(org-social-ui--insert-formatted-text "Loading timeline...\n" nil "#4a90e2")
|
|
|
|
;; Set up the buffer with centering
|
|
(org-social-ui--setup-centered-buffer)
|
|
(goto-char (point-min))
|
|
|
|
;; Load timeline data
|
|
(if (and (boundp 'org-social-relay)
|
|
org-social-relay
|
|
(not (string-empty-p org-social-relay)))
|
|
;; Use relay-first approach
|
|
(progn
|
|
(message "Loading timeline from relay...")
|
|
(org-social-ui--load-timeline-from-relay))
|
|
;; Fallback to local feeds
|
|
(progn
|
|
(message "Loading timeline from local feeds...")
|
|
(org-social-ui--load-timeline-from-feeds)))))
|
|
|
|
(defun org-social-ui--load-timeline-from-relay ()
|
|
"Load timeline from relay server."
|
|
;; For now, fallback to feed method since we need to integrate with existing feed system
|
|
(org-social-ui--load-timeline-from-feeds))
|
|
|
|
(defun org-social-ui--load-timeline-from-feeds ()
|
|
"Load timeline from local feeds."
|
|
(condition-case err
|
|
(progn
|
|
;; Ensure we have required modules
|
|
(require 'org-social-feed)
|
|
(require 'org-social-file)
|
|
|
|
(message "Debug: Checking existing feeds...")
|
|
(message "Debug: org-social-variables--feeds bound: %s" (boundp 'org-social-variables--feeds))
|
|
(when (boundp 'org-social-variables--feeds)
|
|
(message "Debug: org-social-variables--feeds length: %s"
|
|
(if org-social-variables--feeds (length org-social-variables--feeds) 0)))
|
|
|
|
;; Check if we already have feeds loaded
|
|
(if (and (boundp 'org-social-variables--feeds)
|
|
org-social-variables--feeds
|
|
(> (length org-social-variables--feeds) 0))
|
|
;; We have feeds, display them
|
|
(progn
|
|
(message "Debug: Using existing feeds...")
|
|
(let ((timeline (when (fboundp 'org-social-feed--get-timeline)
|
|
(org-social-feed--get-timeline))))
|
|
(message "Debug: Timeline length: %s" (if timeline (length timeline) 0))
|
|
(org-social-ui--check-replies-and-display-timeline timeline)))
|
|
;; No feeds loaded yet, start the loading process
|
|
(progn
|
|
(message "Debug: No feeds loaded, starting initialization...")
|
|
;; Load my profile first to get followers list
|
|
(when (fboundp 'org-social-file--read-my-profile)
|
|
(message "Debug: Reading my profile...")
|
|
(org-social-file--read-my-profile))
|
|
|
|
;; Check if we have relay configured
|
|
(message "Debug: Relay configured: %s"
|
|
(and (boundp 'org-social-relay) org-social-relay (not (string-empty-p org-social-relay))))
|
|
|
|
;; Initialize feeds from relay if available, otherwise from local followers
|
|
(if (and (boundp 'org-social-relay)
|
|
org-social-relay
|
|
(not (string-empty-p org-social-relay))
|
|
(fboundp 'org-social-feed--initialize-queue-from-relay))
|
|
(progn
|
|
(message "Debug: Initializing feeds from relay...")
|
|
(org-social-feed--initialize-queue-from-relay))
|
|
(progn
|
|
(message "Debug: Initializing feeds from local followers...")
|
|
;; Initialize queue from local followers
|
|
(when (fboundp 'org-social-feed--initialize-queue)
|
|
(org-social-feed--initialize-queue)
|
|
(org-social-feed--process-queue))))
|
|
|
|
;; Show message and set up timer to check for loaded feeds
|
|
(org-social-ui--setup-timeline-refresh-timer))))
|
|
(error
|
|
(with-current-buffer org-social-ui--timeline-buffer-name
|
|
(let ((inhibit-read-only t))
|
|
(goto-char (point-max))
|
|
(org-social-ui--insert-formatted-text
|
|
(format "Error loading timeline: %s\n" (error-message-string err))
|
|
nil "#ff0000"))))))
|
|
|
|
(defun org-social-ui--check-replies-and-display-timeline (timeline)
|
|
"Check which posts have replies and then display TIMELINE.
|
|
Only checks posts that will be visible on the current page."
|
|
(if (and timeline
|
|
(> (length timeline) 0)
|
|
(boundp 'org-social-relay)
|
|
org-social-relay
|
|
(not (string-empty-p org-social-relay)))
|
|
(progn
|
|
;; Get only posts for current page
|
|
(let* ((start-idx (* (- org-social-ui--current-page 1) org-social-ui--posts-per-page))
|
|
(end-idx (* org-social-ui--current-page org-social-ui--posts-per-page))
|
|
(visible-posts (cl-subseq timeline
|
|
start-idx
|
|
(min end-idx (length timeline))))
|
|
(post-urls '()))
|
|
;; Extract post URLs only from visible posts
|
|
(dolist (post visible-posts)
|
|
(let* ((author-url (or (alist-get 'author-url post)
|
|
(alist-get 'url post)))
|
|
(timestamp (or (alist-get 'timestamp post)
|
|
(alist-get 'id post)))
|
|
(post-url (when (and author-url timestamp)
|
|
(if (string-empty-p author-url)
|
|
(format "%s#%s"
|
|
(alist-get 'url org-social-variables--my-profile)
|
|
timestamp)
|
|
(format "%s#%s" author-url timestamp)))))
|
|
(when post-url
|
|
(push post-url post-urls))))
|
|
;; Batch check for replies (only for visible posts)
|
|
(if post-urls
|
|
(org-social-relay--check-posts-for-replies
|
|
(nreverse post-urls)
|
|
(lambda (results)
|
|
;; Store results globally
|
|
(setq org-social-variables--posts-with-replies results)
|
|
;; Now display timeline
|
|
(org-social-ui--display-timeline timeline)))
|
|
;; No valid post URLs, just display timeline
|
|
(org-social-ui--display-timeline timeline))))
|
|
;; No timeline or relay not configured, just display
|
|
(org-social-ui--display-timeline timeline)))
|
|
|
|
(defun org-social-ui--check-replies-for-current-page (callback)
|
|
"Check replies for posts in current page and call CALLBACK when done."
|
|
(if (and (boundp 'org-social-relay)
|
|
org-social-relay
|
|
(not (string-empty-p org-social-relay))
|
|
org-social-ui--timeline-current-list)
|
|
(let* ((start-idx (* (- org-social-ui--current-page 1) org-social-ui--posts-per-page))
|
|
(end-idx (* org-social-ui--current-page org-social-ui--posts-per-page))
|
|
(visible-posts (cl-subseq org-social-ui--timeline-current-list
|
|
start-idx
|
|
(min end-idx (length org-social-ui--timeline-current-list))))
|
|
(post-urls '()))
|
|
;; Extract post URLs only from visible posts
|
|
(dolist (post visible-posts)
|
|
(let* ((author-url (or (alist-get 'author-url post)
|
|
(alist-get 'url post)))
|
|
(timestamp (or (alist-get 'timestamp post)
|
|
(alist-get 'id post)))
|
|
(post-url (when (and author-url timestamp)
|
|
(if (string-empty-p author-url)
|
|
(format "%s#%s"
|
|
(alist-get 'url org-social-variables--my-profile)
|
|
timestamp)
|
|
(format "%s#%s" author-url timestamp)))))
|
|
(when post-url
|
|
(push post-url post-urls))))
|
|
;; Check for replies (only for visible posts)
|
|
(if post-urls
|
|
(org-social-relay--check-posts-for-replies
|
|
(nreverse post-urls)
|
|
(lambda (results)
|
|
;; Merge with existing results
|
|
(setq org-social-variables--posts-with-replies
|
|
(append results org-social-variables--posts-with-replies))
|
|
(funcall callback)))
|
|
;; No posts to check, just continue
|
|
(funcall callback)))
|
|
;; No relay configured, just continue
|
|
(funcall callback)))
|
|
|
|
(defun org-social-ui--display-timeline (timeline)
|
|
"Display TIMELINE in the timeline buffer."
|
|
(with-current-buffer org-social-ui--timeline-buffer-name
|
|
(let ((inhibit-read-only t)
|
|
(buffer-read-only nil))
|
|
(goto-char (point-max))
|
|
;; Remove loading message
|
|
(goto-char (point-min))
|
|
(when (search-forward "Loading timeline..." nil t)
|
|
(beginning-of-line)
|
|
(let ((line-start (point)))
|
|
(forward-line 1)
|
|
(delete-region line-start (point))))
|
|
;; Insert posts
|
|
(goto-char (point-max))
|
|
(if (and timeline (> (length timeline) 0))
|
|
(org-social-ui--insert-timeline-posts timeline)
|
|
(org-social-ui--insert-formatted-text
|
|
"No posts available. Check your relay configuration or followed users.\n"
|
|
nil "#888888"))
|
|
;; Enable read-only mode
|
|
(setq buffer-read-only t)
|
|
(goto-char (point-min)))))
|
|
|
|
(defvar org-social-ui--refresh-timer nil
|
|
"Timer for refreshing timeline content.")
|
|
|
|
(defun org-social-ui--setup-timeline-refresh-timer ()
|
|
"Set up a timer to check for loaded feeds and refresh timeline."
|
|
(when org-social-ui--refresh-timer
|
|
(cancel-timer org-social-ui--refresh-timer))
|
|
(setq org-social-ui--refresh-timer
|
|
(run-with-timer 2 1 'org-social-ui--check-and-refresh-timeline)))
|
|
|
|
(defun org-social-ui--check-and-refresh-timeline ()
|
|
"Check if feeds are loaded and refresh timeline if they are."
|
|
(when (and (boundp 'org-social-variables--feeds)
|
|
org-social-variables--feeds
|
|
(> (length org-social-variables--feeds) 0))
|
|
;; Feeds are loaded, cancel timer and display timeline
|
|
(when org-social-ui--refresh-timer
|
|
(cancel-timer org-social-ui--refresh-timer)
|
|
(setq org-social-ui--refresh-timer nil))
|
|
(let ((timeline (when (fboundp 'org-social-feed--get-timeline)
|
|
(org-social-feed--get-timeline))))
|
|
(org-social-ui--check-replies-and-display-timeline timeline)
|
|
(message "Timeline loaded with %d posts" (if timeline (length timeline) 0)))))
|
|
|
|
(defun org-social-ui--timeline-next-page ()
|
|
"Load and append next page of posts (infinite scroll)."
|
|
(interactive)
|
|
(when org-social-ui--timeline-current-list
|
|
(let* ((total-posts (length org-social-ui--timeline-current-list))
|
|
(posts-shown (* org-social-ui--current-page org-social-ui--posts-per-page)))
|
|
(when (< posts-shown total-posts)
|
|
(setq org-social-ui--current-page (1+ org-social-ui--current-page))
|
|
;; Check replies for new page posts
|
|
(org-social-ui--check-replies-for-current-page
|
|
(lambda ()
|
|
;; Append new posts without clearing existing content
|
|
(let ((inhibit-read-only t)
|
|
(buffer-read-only nil))
|
|
(with-current-buffer org-social-ui--timeline-buffer-name
|
|
;; Find and remove the "Show more" button
|
|
(goto-char (point-max))
|
|
(when (search-backward "Show more" nil t)
|
|
(beginning-of-line)
|
|
(let ((start (point)))
|
|
(forward-line 2)
|
|
(delete-region start (point))))
|
|
;; Insert new page of posts
|
|
(goto-char (point-max))
|
|
(let* ((start-idx (* (- org-social-ui--current-page 1) org-social-ui--posts-per-page))
|
|
(end-idx (* org-social-ui--current-page org-social-ui--posts-per-page))
|
|
(posts-to-show (cl-subseq org-social-ui--timeline-current-list
|
|
start-idx
|
|
(min end-idx total-posts))))
|
|
(dolist (post posts-to-show)
|
|
(org-social-ui--post-component post org-social-ui--timeline-current-list)))
|
|
;; Add new "Show more" button if there are more posts
|
|
(when (< (* org-social-ui--current-page org-social-ui--posts-per-page) total-posts)
|
|
(org-social-ui--insert-formatted-text "\n")
|
|
(widget-create 'push-button
|
|
:notify (lambda (&rest _) (org-social-ui--timeline-next-page))
|
|
:help-echo "Load more posts"
|
|
" Show more ")
|
|
(org-social-ui--insert-formatted-text "\n"))
|
|
(setq buffer-read-only t)
|
|
(widget-setup)
|
|
;; Move cursor to the first new post
|
|
;; Find the last separator before "Show more" (or end of buffer)
|
|
(goto-char (point-max))
|
|
(let ((separator-regex (concat "^" (regexp-quote (org-social-ui--string-separator)) "$")))
|
|
;; Go back past "Show more" button if it exists
|
|
(when (search-backward "Show more" nil t)
|
|
(beginning-of-line))
|
|
;; Find the separator of the first new post
|
|
(when (search-backward-regexp separator-regex nil t)
|
|
;; Move to the start of the new post (after separator)
|
|
(forward-line 1)))))))))))
|
|
|
|
(provide 'org-social-ui-timeline)
|
|
;;; org-social-ui-timeline.el ends here
|