Implemented forever scroll. You know you love it.

master
Zed A. Shaw 2 weeks ago
parent 70f9cb089b
commit ebf4e6436b
  1. 9
      api/handlers.go
  2. 1
      static/js/alpine-intersect.js
  3. 35
      static/js/code.js
  4. 9
      views/feed.html
  5. 5
      views/layouts/main.html
  6. 1
      views/post/view.html

@ -24,8 +24,15 @@ func GetApiLogout(c *fiber.Ctx) error {
}
func GetApiFeed(c *fiber.Ctx) error {
sql, args, err := sq.Select("*").From("message").
page := c.QueryInt("page", 0)
if page < 0 { page = 0 }
sql, args, err := sq.Select("*").
Limit(2).
Offset(uint64(2 * page)).
From("message").
Where(sq.Eq{"user_id": c.Params("user_id")}).ToSql()
if err != nil { return IfErrNil(err, c) }
err = data.SelectJson[data.Message](c, err, sql, args...)

@ -0,0 +1 @@
(()=>{function o(e){e.directive("intersect",e.skipDuringClone((t,{value:i,expression:l,modifiers:n},{evaluateLater:r,cleanup:c})=>{let s=r(l),a={rootMargin:x(n),threshold:f(n)},u=new IntersectionObserver(d=>{d.forEach(h=>{h.isIntersecting!==(i==="leave")&&(s(),n.includes("once")&&u.disconnect())})},a);u.observe(t),c(()=>{u.disconnect()})}))}function f(e){if(e.includes("full"))return .99;if(e.includes("half"))return .5;if(!e.includes("threshold"))return 0;let t=e[e.indexOf("threshold")+1];return t==="100"?1:t==="0"?0:Number(`.${t}`)}function p(e){let t=e.match(/^(-?[0-9]+)(px|%)?$/);return t?t[1]+(t[2]||"px"):void 0}function x(e){let t="margin",i="0px 0px 0px 0px",l=e.indexOf(t);if(l===-1)return i;let n=[];for(let r=1;r<5;r++)n.push(p(e[l+r]||""));return n=n.filter(r=>r!==void 0),n.length?n.join(" ").trim():i}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(o)});})();

@ -4,7 +4,7 @@ class PaginateTable {
this.items = [];
this.url = url;
this.headers = [];
this.search_query=""
this.search_query="";
}
async contents() {
@ -31,6 +31,39 @@ class PaginateTable {
}
}
class ForeverScroll {
constructor(url) {
this.page = 0;
this.items = [];
this.url = url;
this.end = false;
}
async init() {
const resp = await fetch(this.url);
console.assert(resp.status == 200, "failed to get it");
const items = await resp.json();
if(items) this.items = items;
}
async load() {
this.page += 1
let url = `${this.url}?page=${this.page}`;
const resp = await fetch(url);
console.assert(resp.status == 200, "failed to get it");
const items = await resp.json();
if(items) {
this.items.push(...items);
} else {
this.end = true;
}
}
}
const GetJson = async (url) => {
const resp = await fetch(url);
console.assert(resp.status == 200, "failed to get it");

@ -28,10 +28,10 @@
{{end}}
<script>
let theFeed = new PaginateTable("/api/feed/1");
let feed = new ForeverScroll('/api/feed/1');
</script>
<div class="p-1" x-data="theFeed">
<div class="p-1" x-data="feed">
<bar class="justify-evenly">
<img src="/favicon.ico" />
<b>Notifications</b>
@ -43,7 +43,7 @@
</svg>
</bar>
<template x-for="message in contents">
<template x-for="message in items">
<block class="!gap-0 border-t-1 border-gray-600">
<bar class="justify-between !p-0 mb-3">
<img src="/favicon.ico" />
@ -57,4 +57,7 @@
{{template "post-action-bar"}}
</block>
</template>
<template x-if="!end"><div x-intersect.full="load()">Loading More...</div></template>
<template x-if="end"><div>The End. Get Back to Work.</div></template>
</div>

@ -8,9 +8,12 @@
<meta name="description" content="My Go learning project, which is a Twitch support thing." />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="/style.css">
<!-- all alpine plugins come first to register into alpine:init event -->
<script defer src="/js/alpine-intersect.js"></script>
<!-- then alpine runs, triggers init, and tada you get no-build plugins -->
<script defer src="/js/alpine.js"></script>
<script src="/js/code.js"></script>
<title>ZedShaw.games</title>
<title>Twitter for Coders Thing</title>
</head>
<body id="top" data-testid="{{.PageId}}">
<header>

@ -2,7 +2,6 @@
<block class="!gap-0 border-t-1 border-gray-600"
x-data="{item: {}}"
x-init="item = await GetJson('/api/message/1')">
<bar class="!p-0 mb-3">
<img src="/logo.png" style="width: 50px; height: 50px" class="aspect-square" />
<block class="justify-between !p-0 !mb-0 !gap-1 *:text-gray-500 *:text-sm">

Loading…
Cancel
Save