diff --git a/package-lock.json b/package-lock.json
index dd11a14a..39e32772 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,8 +8,9 @@
"name": "phanpy",
"version": "0.1.0",
"dependencies": {
- "@github/relative-time-element": "~4.1.5",
"@github/text-expander-element": "~2.3.0",
+ "dayjs": "~1.11.7",
+ "dayjs-twitter": "~0.5.0",
"fast-blurhash": "~1.1.2",
"history": "~5.3.0",
"iconify-icon": "~1.0.2",
@@ -2062,11 +2063,6 @@
"resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.5.tgz",
"integrity": "sha512-dmG1PuppNKHnBBEcfylWDwj9SSxd/E/qd8mC1G/klQC3s7ps5q6JZ034mwkkG0LKfI+Y+UgEua/ROD776N400w=="
},
- "node_modules/@github/relative-time-element": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.1.5.tgz",
- "integrity": "sha512-WAf1EQV5Sn6jGuAIQur/ztKlEV9R+VHDNwqEbeaOb6s9fiwM5z7+ujlWNZtgFkDp3lF0H8D/f0vdiPlfHz0ZTQ=="
- },
"node_modules/@github/text-expander-element": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.3.0.tgz",
@@ -3001,6 +2997,19 @@
"node": ">=8"
}
},
+ "node_modules/dayjs": {
+ "version": "1.11.7",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
+ "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
+ },
+ "node_modules/dayjs-twitter": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/dayjs-twitter/-/dayjs-twitter-0.5.0.tgz",
+ "integrity": "sha512-SZ7qEUISstBLUXdlGAbLrwr6zfRM9kaCfbq4uVTerM/HXzuHiiGzzUqAJVhxt+3tf69E+ocmQdP6YYpOINv05w==",
+ "dependencies": {
+ "duration-js": "^4.0.0"
+ }
+ },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -3060,6 +3069,11 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/duration-js": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/duration-js/-/duration-js-4.0.0.tgz",
+ "integrity": "sha512-qoXjOsH97r+NrOa6sK5V2cwBOouVG/LI9jwgwKvjVkyqGpZ72yilWjjzFJYPqqbvNZDwpRMaLEUFE+PTefvOEA=="
+ },
"node_modules/ejs": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
@@ -7183,11 +7197,6 @@
"resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.5.tgz",
"integrity": "sha512-dmG1PuppNKHnBBEcfylWDwj9SSxd/E/qd8mC1G/klQC3s7ps5q6JZ034mwkkG0LKfI+Y+UgEua/ROD776N400w=="
},
- "@github/relative-time-element": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.1.5.tgz",
- "integrity": "sha512-WAf1EQV5Sn6jGuAIQur/ztKlEV9R+VHDNwqEbeaOb6s9fiwM5z7+ujlWNZtgFkDp3lF0H8D/f0vdiPlfHz0ZTQ=="
- },
"@github/text-expander-element": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.3.0.tgz",
@@ -7925,6 +7934,19 @@
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
"dev": true
},
+ "dayjs": {
+ "version": "1.11.7",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
+ "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
+ },
+ "dayjs-twitter": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/dayjs-twitter/-/dayjs-twitter-0.5.0.tgz",
+ "integrity": "sha512-SZ7qEUISstBLUXdlGAbLrwr6zfRM9kaCfbq4uVTerM/HXzuHiiGzzUqAJVhxt+3tf69E+ocmQdP6YYpOINv05w==",
+ "requires": {
+ "duration-js": "^4.0.0"
+ }
+ },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -7964,6 +7986,11 @@
"tslib": "^2.0.3"
}
},
+ "duration-js": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/duration-js/-/duration-js-4.0.0.tgz",
+ "integrity": "sha512-qoXjOsH97r+NrOa6sK5V2cwBOouVG/LI9jwgwKvjVkyqGpZ72yilWjjzFJYPqqbvNZDwpRMaLEUFE+PTefvOEA=="
+ },
"ejs": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
diff --git a/package.json b/package.json
index ec25be14..0451e333 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,9 @@
"source-map-explorer": "npx source-map-explorer dist/assets/*.js"
},
"dependencies": {
- "@github/relative-time-element": "~4.1.5",
"@github/text-expander-element": "~2.3.0",
+ "dayjs": "~1.11.7",
+ "dayjs-twitter": "~0.5.0",
"fast-blurhash": "~1.1.2",
"history": "~5.3.0",
"iconify-icon": "~1.0.2",
diff --git a/src/components/relative-time.jsx b/src/components/relative-time.jsx
new file mode 100644
index 00000000..7d8c7a14
--- /dev/null
+++ b/src/components/relative-time.jsx
@@ -0,0 +1,57 @@
+// Twitter-style relative time component
+// Seconds = 1s
+// Minutes = 1m
+// Hours = 1h
+// Days = 1d
+// After 7 days, use DD/MM/YYYY or MM/DD/YYYY
+import dayjs from 'dayjs';
+import dayjsTwitter from 'dayjs-twitter';
+import localizedFormat from 'dayjs/plugin/localizedFormat';
+import relativeTime from 'dayjs/plugin/relativeTime';
+import { useEffect, useState } from 'preact/hooks';
+
+dayjs.extend(dayjsTwitter);
+dayjs.extend(localizedFormat);
+dayjs.extend(relativeTime);
+
+const dtf = new Intl.DateTimeFormat();
+
+export default function RelativeTime({ datetime, format }) {
+ if (!datetime) return null;
+ const date = dayjs(datetime);
+ const [dateStr, setDateStr] = useState('');
+
+ useEffect(() => {
+ let timer, raf;
+ const update = () => {
+ raf = requestAnimationFrame(() => {
+ let str;
+ if (format === 'micro') {
+ // If date <= 7 days
+ if (date.diff(dayjs(), 'day') >= -7) {
+ str = date.twitter();
+ } else {
+ // If date > 7 days
+ str = dtf.format(date.toDate());
+ }
+ } else {
+ str = date.fromNow();
+ }
+ setDateStr(str);
+
+ timer = setTimeout(update, 30_000);
+ });
+ };
+ raf = requestAnimationFrame(update);
+ return () => {
+ clearTimeout(timer);
+ cancelAnimationFrame(raf);
+ };
+ }, [date]);
+
+ return (
+
+ );
+}
diff --git a/src/components/status.jsx b/src/components/status.jsx
index ce555c45..a23e0860 100644
--- a/src/components/status.jsx
+++ b/src/components/status.jsx
@@ -28,6 +28,7 @@ import visibilityIconsMap from '../utils/visibility-icons-map';
import Avatar from './avatar';
import Icon from './icon';
+import RelativeTime from './relative-time';
function fetchAccount(id) {
return masto.v1.accounts.fetch(id);
@@ -253,14 +254,7 @@ function Status({
alt={visibility}
size="s"
/>{' '}
-
- Last build:{' '}
-