diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7953637..0b2ef2c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,4 +9,6 @@ deploy:
- echo "@scope:registry=https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" > .npmrc
- echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}" >> .npmrc
- npm publish
+ only:
+ - master
environment: production
diff --git a/CHANGELOG b/CHANGELOG
index 30bbaed..ac629f8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,12 @@
+v4.3.1 - 01/03/2024
+- Show pinned posts
+- Add icon to pinned posts
+- Add '*' character to edited posts
+- Use Intl.DateTimeFormat for date formatting
+- Allow to customize date by locale/options parameters
+- Show user account under user name
+- Added a new customized HTML example
+
v4.2.1 - 26/02/2024
- Changed project name: mastodon-embed-feed-timeline -> mastodon-embed-timeline
- Improved DOM load for module purposes
diff --git a/README.md b/README.md
index 937736c..83ca367 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# đ Mastodon embed timeline (new v4.2)
+# đ Mastodon embed timeline

@@ -24,27 +24,29 @@ Demo running:
## Installation
+You have three different ways to install it in your project, choose the one that best suits your needs:
+
### Download
-Ready-to-use compiled and minified files to easily start.
+Download into your project the following compiled and minified files:
-- Download into your project the following files:
- - `dist/mastodon-timeline.min.css`
- - `dist/mastodon-timeline.umd.js`
+- `dist/mastodon-timeline.min.css`
+- `dist/mastodon-timeline.umd.js`
Now call the CSS and JS files in your HTML page using the `` and `
+
```
### Package manager
-Install your Mastodon timeline using npm or yarn:
+A quick way to get it installed using **npm** or **yarn**:
```terminal
npm install @idotj/mastodon-embed-timeline
@@ -84,19 +86,19 @@ or
yarn add @idotj/mastodon-embed-timeline
```
-After installation, you can import the widget as follows:
+After installation, you can import the Javascript as follows:
```js
import * as MastodonTimeline from "@idotj/mastodon-embed-timeline";
```
-Make sure to import also the `@idotj/mastodon-embed-timeline/dist/mastodon-timeline.min.css` file in your project.
+Make sure to import also the file `mastodon-timeline.min.css` into your project.
## Setup
### Initialize
-The first step to get your timeline up is to add the following HTML structure in your page:
+To get your timeline up add the following HTML structure in your page:
```html
@@ -124,11 +126,11 @@ window.addEventListener("load", () => {
});
```
-The next step is to configure the options/values of your timeline according to the type you need. There are three types, **Local**, **Profile** and **Hashtag**:
+The next step is to configure the options/values of your timeline according to the type you prefer. There are three types, **Local**, **Profile** and **Hashtag**. Here you have an example of each one to see how it works:
#### Local timeline
-Add the following option/value when initializing the timeline:
+To show a timeline with posts from the instance [mastodon.online](https://mastodon.online/public/local) add the following option/value when initializing the timeline:
```js
const myTimeline = new MastodonTimeline.Init({
@@ -136,11 +138,9 @@ const myTimeline = new MastodonTimeline.Init({
});
```
-It will show a timeline with posts from the instance [mastodon.online](https://mastodon.online/public/local)
-
#### Profile timeline
-Add the following options/values when initializing the timeline:
+To show a timeline with posts from my Mastodon profile [@idotj](https://mastodon.online/@idotj) add the following options/values when initializing the timeline:
```js
const myTimeline = new MastodonTimeline.Init({
@@ -151,8 +151,6 @@ const myTimeline = new MastodonTimeline.Init({
});
```
-It will show a timeline with posts from my Mastodon profile [@idotj](https://mastodon.online/@idotj)
-
âšī¸ If you don't know your `userId` you have two ways to get it:
- Copy the url below and paste it in a new tab. Remember to replace the words `INSTANCE` and `USERNAME` with your current values in the url:
@@ -164,7 +162,7 @@ It will show a timeline with posts from my Mastodon profile [@idotj](https://mas
#### Hashtag timeline
-Add the following options/values when initializing the timeline:
+To show a timeline with posts containing the hashtag [#fediverse](https://mastodon.online/tags/fediverse) add the following options/values when initializing the timeline:
```js
const myTimeline = new MastodonTimeline.Init({
@@ -174,68 +172,106 @@ const myTimeline = new MastodonTimeline.Init({
});
```
-It will show a timeline with posts containing the hashtag [#fediverse](https://mastodon.online/tags/fediverse)
-
### Customize
-You can pass more options/values to personalize your timeline. Here you have all the available options:
+In the `examples/` folder there is an HTML file `local-timeline-customized.html` where you can see how to customize your timeline by overwriting the CSS styles and using various JS options when initializing the timeline.
+
+If you need to change something in the core files (`src/` folder), I recommend you to read the document [CONTRIBUTING.md](https://gitlab.com/idotj/mastodon-embed-timeline/-/blob/master/CONTRIBUTING.md#testing) to see how to compile and test your changes.
+
+Here you have all the options available to quickly setup and customize your timeline:
```js
// Id of the
containing the timeline
mtContainerId: "mt-container",
- // Mastodon instance Url (including https://)
+ // Mastodon instance Url including https://
instanceUrl: "https://mastodon.social",
- // Choose type of posts to show in the timeline: 'local', 'profile', 'hashtag'. Default: local
+ // Choose type of posts to show in the timeline: 'local', 'profile', 'hashtag'
+ // Default: local
timelineType: "local",
- // Your user ID number on Mastodon instance. Leave it empty if you didn't choose 'profile' as type of timeline
+ // Your user ID number on Mastodon instance
+ // Leave it empty if you didn't choose 'profile' as type of timeline
userId: "",
- // Your user name on Mastodon instance (including the @ symbol at the beginning). Leave it empty if you didn't choose 'profile' as type of timeline
+ // Your user name on Mastodon instance (including the @ symbol at the beginning)
+ // Leave it empty if you didn't choose 'profile' as type of timeline
profileName: "",
- // The name of the hashtag (not including the # symbol). Leave it empty if you didn't choose 'hashtag' as type of timeline
+ // The name of the hashtag (not including the # symbol)
+ // Leave it empty if you didn't choose 'hashtag' as type of timeline
hashtagName: "",
// Class name for the loading spinner (also used in CSS file)
spinnerClass: "mt-loading-spinner",
- // Preferred color theme: 'light', 'dark' or 'auto'. Default: auto
+ // Preferred color theme: 'light', 'dark' or 'auto'
+ // Default: auto
defaultTheme: "auto",
- // Maximum number of posts to request to the server. Default: 20
+ // Maximum number of posts to request to the server
+ // Default: 20
maxNbPostFetch: "20",
- // Maximum number of posts to show in the timeline. Default: 20
+ // Maximum number of posts to show in the timeline
+ // Default: 20
maxNbPostShow: "20",
- // Hide unlisted posts. Default: don't hide
+ // Specifies the format of the date according to the chosen language/country
+ // Default: British English (day-month-year order)
+ dateLocale: "en-GB",
+
+ // Customize the date format using the options
+ // Default: DD MMM YYYY
+ dateOptions: {
+ day: "2-digit",
+ month: "short",
+ year: "numeric",
+ },
+
+ // Hide unlisted posts
+ // Default: don't hide
hideUnlisted: false,
- // Hide boosted posts. Default: don't hide
+ // Hide boosted posts
+ // Default: don't hide
hideReblog: false,
- // Hide replies posts. Default: don't hide
+ // Hide replies posts
+ // Default: don't hide
hideReplies: false,
- // Hide video image preview and load video player instead. Default: don't hide
- hideVideoPreview: false,
+ // Hide pinned posts from the profile timeline
+ // Default: don't hide
+ hidePinnedPosts: false,
- // Hide preview card if post contains a link, photo or video from a Url. Default: don't hide
- hidePreviewLink: false,
+ // Hide user account under the user name
+ // Default: don't hide
+ hideUserAccount: false,
- // Hide custom emojis available on the server. Default: don't hide
+ // Hide custom emojis available on the server
+ // Default: don't hide
hideEmojos: false,
- // Converts Markdown symbol ">" at the beginning of a paragraph into a blockquote HTML tag. Default: don't apply
- markdownBlockquote: false,
+ // Hide video image preview and load video player instead
+ // Default: don't hide
+ hideVideoPreview: false,
- // Hide replies, boosts and favourites posts counter. Default: don't hide
+ // Hide preview card if post contains a link, photo or video from a Url
+ // Default: don't hide
+ hidePreviewLink: false,
+
+ // Hide replies, boosts and favourites posts counter
+ // Default: don't hide
hideCounterBar: false,
- // Limit the text content to a maximum number of lines. Default: 0 (unlimited)
+ // Converts Markdown symbol ">" at the beginning of a paragraph into a blockquote HTML tag
+ // Default: don't apply
+ markdownBlockquote: false,
+
+ // Limit the text content to a maximum number of lines
+ // Default: 0 (unlimited)
txtMaxLines: "0",
// Customize the text of the button used for showing/hiding sensitive/spolier text
@@ -245,16 +281,20 @@ You can pass more options/values to personalize your timeline. Here you have all
// Customize the text of the button used for showing sensitive/spolier media content
btnShowContent: "SHOW CONTENT",
- // Customize the text of the button pointing to the Mastodon page placed at the end of the timeline. Leave the value empty to hide it
+ // Customize the text of the button pointing to the Mastodon page placed at the end of the timeline
+ // Leave the value empty to hide it
btnSeeMore: "See more posts at Mastodon",
- // Customize the text of the button reloading the list of posts placed at the end of the timeline. Leave the value empty to hide it
+ // Customize the text of the button reloading the list of posts placed at the end of the timeline
+ // Leave the value empty to hide it
btnReload: "Refresh",
- // Keep searching for the main
container before building the timeline. Useful in some cases where extra time is needed to render the page. Default: false
+ // Keep searching for the main
container before building the timeline. Useful in some cases where extra time is needed to render the page
+ // Default: don't apply
insistSearchContainer: false,
- // Defines the maximum time to continue searching for the main
container. Default: 3 seconds
+ // Defines the maximum time to continue searching for the main
container
+ // Default: 3 seconds
insistSearchContainerTime: "3000",
```
@@ -270,7 +310,7 @@ You can pass more options/values to personalize your timeline. Here you have all
The folder `examples/` contains several demos in HTML to play with. Download the full project and open each HTML file in your favorite browser.
-Also, you have other alternatives to run these examples locally. Consult the document [CONTRIBUTING.md](https://gitlab.com/idotj/mastodon-embed-timeline/-/blob/master/CONTRIBUTING.md#testing) to use other options like Docker or Http-server.
+Also, you have other alternatives to run these examples locally. Consult the document [CONTRIBUTING.md](https://gitlab.com/idotj/mastodon-embed-timeline/-/blob/master/CONTRIBUTING.md#testing) to use options such as Docker or Http-server.
## đ Browser support
diff --git a/dist/mastodon-timeline.esm.js b/dist/mastodon-timeline.esm.js
index c554b54..c11751f 100644
--- a/dist/mastodon-timeline.esm.js
+++ b/dist/mastodon-timeline.esm.js
@@ -1,8 +1,8 @@
-/**
- * Mastodon embed timeline
- * @author idotj
- * @version 4.2.1
- * @url https://gitlab.com/idotj/mastodon-embed-timeline
- * @license GNU AGPLv3
- */
-class t{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hideVideoPreview:!1,hidePreviewLink:!1,hideEmojos:!1,markdownBlockquote:!1,hideCounterBar:!1,txtMaxLines:"0",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",btnShowContent:"SHOW CONTENT",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#t((()=>{this.#e()}))}#t(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#e(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#i("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),s=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};s()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#t((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",''),this.#i("updateTimeline")}))}mtColorTheme(t){this.#t((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#a(){return new Promise(((t,e)=>{let s={};this.mtSettings.instanceUrl?"profile"===this.mtSettings.timelineType?this.mtSettings.userId?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your userId value","â ī¸"):"hashtag"===this.mtSettings.timelineType?this.mtSettings.hashtagName?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your hashtagName value","â ī¸"):"local"===this.mtSettings.timelineType?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your timelineType value","â ī¸"):this.#o("Please check your instanceUrl value","â ī¸"),this.mtSettings.hideEmojos||(s.emojos=this.mtSettings.instanceUrl+"/api/v1/custom_emojis");const i=Object.entries(s).map((([t,s])=>async function(t){const e=await fetch(t);if(!e.ok)throw new Error("Failed to fetch the following Url: "+t+"Error status: "+e.status+"Error message: "+e.statusText);return await e.json()}(s).then((e=>({[t]:e}))).catch((i=>(e(new Error("Something went wrong fetching data from: "+s)),this.#o(i.message),{[t]:[]})))));Promise.all(i).then((e=>{this.mtSettings.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),t()}))}))}async#i(t){await this.#a(),this.mtBodyNode.replaceChildren();let e=0;for(let t in this.mtSettings.fetchedData.timeline)("public"==this.mtSettings.fetchedData.timeline[t].visibility||!this.mtSettings.hideUnlisted&&"unlisted"==this.mtSettings.fetchedData.timeline[t].visibility)&&(this.mtSettings.hideReblog&&this.mtSettings.fetchedData.timeline[t].reblog||this.mtSettings.hideReplies&&this.mtSettings.fetchedData.timeline[t].in_reply_to_id||eThis may be due to an incorrect configuration in the parameters or to filters applied (to hide certains type of posts)";this.#o(t,"đ")}else"newTimeline"===t?(this.#r(),this.#l(),this.#m()):"updateTimeline"===t?this.#r():this.#o("The function buildTimeline() was expecting a param")}#n(t,e){this.mtBodyNode.insertAdjacentHTML("beforeend",this.#d(t,e))}#d(t,e){let s,i,a,o,n,r,l,m,d;t.reblog?(o=t.reblog.url,s='
";let g=[];if(t.media_attachments.length>0)for(let e in t.media_attachments)g.push(this.#u(t.media_attachments[e],t.sensitive));if(t.reblog&&t.reblog.media_attachments.length>0)for(let e in t.reblog.media_attachments)g.push(this.#u(t.reblog.media_attachments[e],t.reblog.sensitive));let u="";!this.mtSettings.hidePreviewLink&&t.card&&(u=this.#v(t.card));let v="";if(t.poll){let e="";for(let s in t.poll.options)e+="
",this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}export{t as Init};
+/**
+ * Mastodon embed timeline
+ * @author idotj
+ * @version 4.3.1
+ * @url https://gitlab.com/idotj/mastodon-embed-timeline
+ * @license GNU AGPLv3
+ */
+class t{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",dateLocale:"en-GB",dateOptions:{day:"2-digit",month:"short",year:"numeric"},hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hidePinnedPosts:!1,hideUserAccount:!1,hideEmojos:!1,hideVideoPreview:!1,hidePreviewLink:!1,hideCounterBar:!1,markdownBlockquote:!1,txtMaxLines:"0",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",btnShowContent:"SHOW CONTENT",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#t((()=>{this.#e()}))}#t(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#e(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#i("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),s=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};s()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#t((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",''),this.#i("updateTimeline")}))}mtColorTheme(t){this.#t((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#a(){return new Promise(((t,e)=>{let s={};this.mtSettings.instanceUrl?"profile"===this.mtSettings.timelineType?this.mtSettings.userId?(s.timeline=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`,this.mtSettings.hidePinnedPosts||(s.pinned=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?pinned=true`)):this.#o("Please check your userId value","â ī¸"):"hashtag"===this.mtSettings.timelineType?this.mtSettings.hashtagName?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your hashtagName value","â ī¸"):"local"===this.mtSettings.timelineType?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your timelineType value","â ī¸"):this.#o("Please check your instanceUrl value","â ī¸"),this.mtSettings.hideEmojos||(s.emojos=this.mtSettings.instanceUrl+"/api/v1/custom_emojis");const i=Object.entries(s).map((([t,s])=>async function(t){const e=await fetch(t);if(!e.ok)throw new Error("Failed to fetch the following Url: "+t+"Error status: "+e.status+"Error message: "+e.statusText);return await e.json()}(s).then((e=>({[t]:e}))).catch((i=>(e(new Error("Something went wrong fetching data from: "+s)),this.#o(i.message),{[t]:[]})))));Promise.all(i).then((e=>{this.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),t()}))}))}async#i(t){let e;if(await this.#a(),this.mtSettings.hidePinnedPosts||void 0===this.fetchedData.pinned?.length||0===this.fetchedData.pinned.length)e=this.fetchedData.timeline;else{e=[...this.fetchedData.pinned.map((t=>({...t,pinned:!0}))),...this.fetchedData.timeline]}this.mtBodyNode.replaceChildren();let s=0;for(let t in e)("public"==e[t].visibility||!this.mtSettings.hideUnlisted&&"unlisted"==e[t].visibility)&&(this.mtSettings.hideReblog&&e[t].reblog||this.mtSettings.hideReplies&&e[t].in_reply_to_id||sThis may be due to an incorrect configuration in the parameters or to filters applied (to hide certains type of posts)";this.#o(t,"đ")}else"newTimeline"===t?(this.#r(),this.#l(),this.#m()):"updateTimeline"===t?this.#r():this.#o("The function buildTimeline() was expecting a param")}#n(t,e){this.mtBodyNode.insertAdjacentHTML("beforeend",this.#d(t,e))}#d(t,e){let s,i,a,o,n,r,l,m,d,h;t.reblog?(n=t.reblog.url,s='
";let u=[];if(t.media_attachments.length>0)for(let e in t.media_attachments)u.push(this.#u(t.media_attachments[e],t.sensitive));if(t.reblog&&t.reblog.media_attachments.length>0)for(let e in t.reblog.media_attachments)u.push(this.#u(t.reblog.media_attachments[e],t.reblog.sensitive));let v="";!this.mtSettings.hidePreviewLink&&t.card&&(v=this.#v(t.card));let b="";if(t.poll){let e="";for(let s in t.poll.options)e+="
",this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}export{t as Init};
diff --git a/dist/mastodon-timeline.min.css b/dist/mastodon-timeline.min.css
index 4edb1b4..cc72e67 100644
--- a/dist/mastodon-timeline.min.css
+++ b/dist/mastodon-timeline.min.css
@@ -1 +1 @@
-.mt-container,.mt-container[data-theme=light]{--mt-txt-max-lines:none;--mt-color-bg:#fff;--mt-color-bg-hover:#d9e1e8;--mt-color-line-gray:#c0cdd9;--mt-color-contrast-gray:#606984;--mt-color-content-txt:#000;--mt-color-link:#3a3bff;--mt-color-error-txt:#8b0000;--mt-color-btn-bg:#6364ff;--mt-color-btn-bg-hover:#563acc;--mt-color-btn-txt:#fff}.mt-container[data-theme=dark]{--mt-color-bg:#282c37;--mt-color-bg-hover:#313543;--mt-color-line-gray:#393f4f;--mt-color-contrast-gray:#606984;--mt-color-content-txt:#fff;--mt-color-link:#8c8dff;--mt-color-error-txt:#fe6c6c}.mt-container button{font:inherit}.mt-container a,.mt-container button{cursor:pointer}.mt-container{display:flex;flex-direction:column;height:100%;overflow-y:auto;position:relative;background-color:var(--mt-color-bg);scrollbar-color:var(--mt-color-contrast-gray) var(--mt-color-bg);scrollbar-width:auto}.mt-container::-webkit-scrollbar{width:.25rem;height:.25rem}.mt-container::-webkit-scrollbar-thumb{background-color:var(--mt-color-contrast-gray);border:none;border-radius:3rem}.mt-container::-webkit-scrollbar-thumb:active,.mt-container::-webkit-scrollbar-thumb:hover{background-color:var(--mt-color-contrast-gray)}.mt-container::-webkit-scrollbar-track{background-color:var(--mt-color-bg);border:none;border-radius:0}.mt-container::-webkit-scrollbar-corner,.mt-container::-webkit-scrollbar-track:active,.mt-container::-webkit-scrollbar-track:hover{background-color:var(--mt-color-bg)}.mt-container a,.mt-container a:active,.mt-container a:link{text-decoration:none;color:var(--mt-color-link)}.mt-container a:not(.mt-post-preview):hover{text-decoration:underline}.mt-body{padding:1rem clamp(.25rem,4vw,1rem);white-space:pre-wrap;word-wrap:break-word;margin-bottom:1rem}.mt-body .invisible{font-size:0;line-height:0;display:inline-block;width:0;height:0;position:absolute}.mt-post{margin:.25rem;padding:1rem .5rem;position:relative;min-height:3.75rem;background-color:transparent;border-bottom:1px solid var(--mt-color-line-gray)}.mt-post:focus,.mt-post:hover{cursor:pointer;background-color:var(--mt-color-bg-hover)}.mt-post p:last-child{margin-bottom:0}.mt-post-avatar{margin-right:.75rem}.mt-post-avatar-standard{width:2.25rem;height:2.25rem}.mt-post-avatar-boosted{width:3rem;height:3rem;position:relative}.mt-post-avatar-image-big img{aspect-ratio:1/1;width:2.25rem;height:2.25rem;border-radius:.25rem;overflow:hidden}.mt-post-avatar-image-small img{aspect-ratio:1/1;width:1.5rem;height:1.5rem;top:1.5rem;left:1.5rem;position:absolute;border-radius:.25rem;overflow:hidden}.mt-post-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1rem}.mt-post-header-user{font-weight:600;margin-top:.5rem;padding-right:1rem}.mt-post-header-user>a{display:flex;align-items:flex-start;color:var(--mt-color-content-txt)!important;overflow-wrap:anywhere}.mt-post-header-date{font-size:.75rem;text-align:right;margin:.5rem 0 0 auto}.mt-post-header-date>a{color:var(--mt-color-contrast-gray)!important}.mt-post-txt{margin-bottom:1rem;color:var(--mt-color-content-txt)}.mt-post-txt .spoiler-txt-hidden{display:none}.mt-post-txt.truncate{display:-webkit-box;overflow:hidden;-webkit-line-clamp:var(--mt-txt-max-lines);-webkit-box-orient:vertical}.mt-post-txt:not(.truncate) .ellipsis::after{content:"..."}.mt-post-txt blockquote{border-left:.25rem solid var(--mt-color-line-gray);margin-left:0;padding-left:.5rem}.mt-post-header-user .mt-custom-emoji,.mt-post-txt .mt-custom-emoji{height:1.5rem;min-width:1.5rem;margin-bottom:-.25rem;width:auto}.mt-post-poll{margin-bottom:1rem;color:var(--mt-color-content-txt)}.mt-post-poll ul{list-style:none;padding:0;margin:0}.mt-post-poll ul li{font-size:.9rem;margin-bottom:.5rem}.mt-post-poll.mt-post-poll-expired ul li{color:var(--mt-color-contrast-gray)}.mt-post-poll ul li:not(:last-child){margin-bottom:.25rem}.mt-post-poll ul li:before{content:"â¯";padding-right:.5rem}.mt-post-poll.mt-post-poll-expired ul li:before{content:"";padding-right:0}.mt-post-media{position:relative;overflow:hidden;margin-bottom:1rem}.mt-post-media-spoiler>.mt-post-media-play-icon,.mt-post-media-spoiler>audio,.mt-post-media-spoiler>img,.mt-post-media-spoiler>video{filter:blur(2rem);pointer-events:none}.mt-post-media>audio{width:100%;position:relative;z-index:1}.mt-post-media>img,.mt-post-media>video{width:100%;height:100%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:var(--mt-color-content-txt)}.mt-post-media.mt-loading-spinner .mt-post-media-play-icon{display:none}.mt-post-media-play-icon{display:flex;position:absolute;width:3rem;height:3rem;top:calc(50% - 1.5rem);left:calc(50% - 1.5rem);justify-content:center;align-items:center;background-color:transparent;border:none;cursor:pointer}.mt-post-media-play-icon>svg{width:2.5rem;height:2.5rem;fill:var(--mt-color-bg);stroke:var(--mt-color-content-txt);stroke-width:1px}.mt-post-preview{min-height:4rem;display:flex;flex-direction:row;border:1px solid var(--mt-color-line-gray);border-radius:.5rem;color:var(--mt-color-link);font-size:.8rem;margin:1rem 0;overflow:hidden}.mt-post-preview-image{width:40%;align-self:stretch}.mt-post-preview-image img{display:block;width:100%;height:100%;object-fit:cover;color:var(--mt-color-content-txt)}.mt-post-preview-noImage{width:40%;font-size:1.5rem;align-self:center;text-align:center}.mt-post-preview-content{width:60%;display:flex;align-self:center;flex-direction:column;padding:.5rem 1rem;gap:.5rem}.mt-post-preview-title{font-weight:600}.mt-post-counter-bar{display:flex;min-width:6rem;max-width:40rem;justify-content:space-between;color:var(--mt-color-contrast-gray)}.mt-post-counter-bar-favorites,.mt-post-counter-bar-reblog,.mt-post-counter-bar-replies{display:flex;font-size:.75rem;gap:.25rem;align-items:center;opacity:.5}.mt-post-counter-bar-favorites>svg,.mt-post-counter-bar-reblog>svg,.mt-post-counter-bar-replies>svg{width:1rem;fill:var(--mt-color-contrast-gray)}.mt-container .mt-btn-dark{display:flex;border-radius:.25rem;background-color:var(--mt-color-line-gray);border:0;color:var(--mt-color-content-txt);font-weight:600;font-size:.75rem;text-align:center;padding:0 .5rem;line-height:1.25rem;vertical-align:top}.mt-container .mt-btn-violet,.mt-container a.mt-btn-violet{display:flex;align-items:center;gap:.5rem;border-radius:.25rem;border:.5rem;padding:.5rem .75rem;font-size:1rem;font-weight:600;text-align:center;background-color:var(--mt-color-btn-bg);color:var(--mt-color-btn-txt)}.mt-container .mt-btn-violet:hover,.mt-container a.mt-btn-violet:hover{background-color:var(--mt-color-btn-bg-hover);text-decoration:none}.mt-post-txt .mt-btn-spoiler{display:inline-block}.mt-post-media.mt-loading-spinner>.mt-btn-spoiler{display:none}.mt-post-media>.mt-btn-spoiler{position:absolute;top:50%;left:50%;z-index:2;transform:translate(-50%,-50%)}.mt-error{position:absolute;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;height:calc(100% - 3.5rem);width:calc(100% - 4.5rem);justify-content:center;align-items:center;color:var(--mt-color-error-txt);padding:.75rem;text-align:center}.mt-error-icon{font-size:2rem}.mt-error-message{width:100%;padding:1rem 0}.mt-error-message hr{color:var(--mt-color-line-gray)}.mt-body>.mt-loading-spinner{position:absolute;width:3rem;height:3rem;margin:auto;top:calc(50% - 1.5rem);right:calc(50% - 1.5rem)}.mt-loading-spinner{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cg%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 64 64' to='360 64 64' dur='1000ms' repeatCount='indefinite'/%3E%3Cpath d='M64 6.69a57.3 57.3 0 1 1 0 114.61A57.3 57.3 0 0 1 6.69 64' fill='none' stroke='%23404040' stroke-width='12'/%3E%3C/g%3E%3C/svg%3E");background-repeat:no-repeat;background-position:center center;background-color:transparent;background-size:min(2.5rem,calc(100% - .5rem))}.mt-footer{display:flex;flex-flow:wrap;margin:auto auto 2rem auto;padding:0 1.5rem;gap:1.5rem;align-items:center;justify-content:center}.visually-hidden{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}
\ No newline at end of file
+.mt-container,.mt-container[data-theme=light]{--mt-txt-max-lines:none;--mt-color-bg:#fff;--mt-color-bg-hover:#d9e1e8;--mt-color-line-gray:#c0cdd9;--mt-color-contrast-gray:#606984;--mt-color-content-txt:#000;--mt-color-link:#3a3bff;--mt-color-error-txt:#8b0000;--mt-color-btn-bg:#6364ff;--mt-color-btn-bg-hover:#563acc;--mt-color-btn-txt:#fff}.mt-container[data-theme=dark]{--mt-color-bg:#282c37;--mt-color-bg-hover:#313543;--mt-color-line-gray:#393f4f;--mt-color-contrast-gray:#606984;--mt-color-content-txt:#fff;--mt-color-link:#8c8dff;--mt-color-error-txt:#fe6c6c}.mt-container button{font:inherit}.mt-container a,.mt-container button{cursor:pointer}.mt-container{display:flex;flex-direction:column;height:100%;overflow-y:auto;position:relative;background-color:var(--mt-color-bg);scrollbar-color:var(--mt-color-contrast-gray) var(--mt-color-bg);scrollbar-width:auto}.mt-container::-webkit-scrollbar{width:.25rem;height:.25rem}.mt-container::-webkit-scrollbar-thumb{background-color:var(--mt-color-contrast-gray);border:none;border-radius:3rem}.mt-container::-webkit-scrollbar-thumb:active,.mt-container::-webkit-scrollbar-thumb:hover{background-color:var(--mt-color-contrast-gray)}.mt-container::-webkit-scrollbar-track{background-color:var(--mt-color-bg);border:none;border-radius:0}.mt-container::-webkit-scrollbar-corner,.mt-container::-webkit-scrollbar-track:active,.mt-container::-webkit-scrollbar-track:hover{background-color:var(--mt-color-bg)}.mt-container a,.mt-container a:active,.mt-container a:link{text-decoration:none;color:var(--mt-color-link)}.mt-container a:not(.mt-post-preview):hover{text-decoration:underline}.mt-body{padding:1rem clamp(.25rem,4vw,1rem);white-space:pre-wrap;word-wrap:break-word;margin-bottom:1rem}.mt-body .invisible{font-size:0;line-height:0;display:inline-block;width:0;height:0;position:absolute}.mt-post{margin:.25rem;padding:1rem .5rem;position:relative;min-height:3.75rem;background-color:transparent;border-bottom:1px solid var(--mt-color-line-gray)}.mt-post:focus,.mt-post:hover{cursor:pointer;background-color:var(--mt-color-bg-hover)}.mt-post p:last-child{margin-bottom:0}.mt-post-avatar{margin-right:.75rem}.mt-post-avatar-standard{width:2.25rem;height:2.25rem}.mt-post-avatar-boosted{width:3rem;height:3rem;position:relative}.mt-post-avatar-image-big img{aspect-ratio:1/1;width:2.25rem;height:2.25rem;border-radius:.25rem;overflow:hidden}.mt-post-avatar-image-small img{aspect-ratio:1/1;width:1.5rem;height:1.5rem;top:1.5rem;left:1.5rem;position:absolute;border-radius:.25rem;overflow:hidden}.mt-post-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1rem}.mt-post-header-user{overflow:hidden;padding-right:.75rem}.mt-post-header-user>a{color:var(--mt-color-content-txt)!important;overflow-wrap:anywhere}.mt-container .mt-post-header-user>a:hover{text-decoration:none}.mt-post-header-user-name{font-weight:600}.mt-container .mt-post-header-user:hover .mt-post-header-user-name{text-decoration:underline}.mt-post-header-user-account{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--mt-color-contrast-gray)}.mt-post-header-date{display:flex;font-size:.75rem;text-align:right;margin-left:auto}.mt-post-header-date .mt-post-pinned{width:1.25rem;margin-top:-.25rem;fill:var(--mt-color-contrast-gray)}.mt-container .mt-post-header-date>a{white-space:nowrap;color:var(--mt-color-contrast-gray)!important}.mt-post-txt{margin-bottom:1rem;color:var(--mt-color-content-txt)}.mt-post-txt .spoiler-txt-hidden{display:none}.mt-post-txt.truncate{display:-webkit-box;overflow:hidden;-webkit-line-clamp:var(--mt-txt-max-lines);-webkit-box-orient:vertical}.mt-post-txt:not(.truncate) .ellipsis::after{content:"..."}.mt-post-txt blockquote{border-left:.25rem solid var(--mt-color-line-gray);margin-left:0;padding-left:.5rem}.mt-post-header-user .mt-custom-emoji,.mt-post-txt .mt-custom-emoji{height:1.5rem;min-width:1.5rem;margin-bottom:-.25rem;width:auto}.mt-post-poll{margin-bottom:1rem;color:var(--mt-color-content-txt)}.mt-post-poll ul{list-style:none;padding:0;margin:0}.mt-post-poll ul li{font-size:.9rem;margin-bottom:.5rem}.mt-post-poll.mt-post-poll-expired ul li{color:var(--mt-color-contrast-gray)}.mt-post-poll ul li:not(:last-child){margin-bottom:.25rem}.mt-post-poll ul li:before{content:"â¯";padding-right:.5rem}.mt-post-poll.mt-post-poll-expired ul li:before{content:"";padding-right:0}.mt-post-media{position:relative;overflow:hidden;margin-bottom:1rem}.mt-post-media-spoiler>.mt-post-media-play-icon,.mt-post-media-spoiler>audio,.mt-post-media-spoiler>img,.mt-post-media-spoiler>video{filter:blur(2rem);pointer-events:none}.mt-post-media>audio{width:100%;position:relative;z-index:1}.mt-post-media>img,.mt-post-media>video{width:100%;height:100%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:var(--mt-color-content-txt)}.mt-post-media.mt-loading-spinner .mt-post-media-play-icon{display:none}.mt-post-media-play-icon{display:flex;position:absolute;width:3rem;height:3rem;top:calc(50% - 1.5rem);left:calc(50% - 1.5rem);justify-content:center;align-items:center;background-color:transparent;border:none;cursor:pointer}.mt-post-media-play-icon>svg{width:2.5rem;height:2.5rem;fill:var(--mt-color-bg);stroke:var(--mt-color-content-txt);stroke-width:1px}.mt-post-preview{min-height:4rem;display:flex;flex-direction:row;border:1px solid var(--mt-color-line-gray);border-radius:.5rem;color:var(--mt-color-link);font-size:.8rem;margin:1rem 0;overflow:hidden}.mt-post-preview-image{width:40%;align-self:stretch}.mt-post-preview-image img{display:block;width:100%;height:100%;object-fit:cover;color:var(--mt-color-content-txt)}.mt-post-preview-noImage{width:40%;font-size:1.5rem;align-self:center;text-align:center}.mt-post-preview-content{width:60%;display:flex;align-self:center;flex-direction:column;padding:.5rem 1rem;gap:.5rem}.mt-post-preview-title{font-weight:600}.mt-post-counter-bar{display:flex;min-width:6rem;max-width:40rem;justify-content:space-between;color:var(--mt-color-contrast-gray)}.mt-post-counter-bar-favorites,.mt-post-counter-bar-reblog,.mt-post-counter-bar-replies{display:flex;font-size:.75rem;gap:.25rem;align-items:center;opacity:.5}.mt-post-counter-bar-favorites>svg,.mt-post-counter-bar-reblog>svg,.mt-post-counter-bar-replies>svg{width:1rem;fill:var(--mt-color-contrast-gray)}.mt-container .mt-btn-dark{display:flex;border-radius:.25rem;background-color:var(--mt-color-line-gray);border:0;color:var(--mt-color-content-txt);font-weight:600;font-size:.75rem;text-align:center;padding:0 .5rem;line-height:1.25rem;vertical-align:top}.mt-container .mt-btn-violet,.mt-container a.mt-btn-violet{display:flex;align-items:center;gap:.5rem;border-radius:.25rem;border:.5rem;padding:.5rem .75rem;font-size:1rem;font-weight:600;text-align:center;background-color:var(--mt-color-btn-bg);color:var(--mt-color-btn-txt)}.mt-container .mt-btn-violet:hover,.mt-container a.mt-btn-violet:hover{background-color:var(--mt-color-btn-bg-hover);text-decoration:none}.mt-post-txt .mt-btn-spoiler{display:inline-block}.mt-post-media.mt-loading-spinner>.mt-btn-spoiler{display:none}.mt-post-media>.mt-btn-spoiler{position:absolute;top:50%;left:50%;z-index:2;transform:translate(-50%,-50%)}.mt-error{position:absolute;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;height:calc(100% - 3.5rem);width:calc(100% - 4.5rem);justify-content:center;align-items:center;color:var(--mt-color-error-txt);padding:.75rem;text-align:center}.mt-error-icon{font-size:2rem}.mt-error-message{width:100%;padding:1rem 0}.mt-error-message hr{color:var(--mt-color-line-gray)}.mt-body>.mt-loading-spinner{position:absolute;width:3rem;height:3rem;margin:auto;top:calc(50% - 1.5rem);right:calc(50% - 1.5rem)}.mt-loading-spinner{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cg%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 64 64' to='360 64 64' dur='1000ms' repeatCount='indefinite'/%3E%3Cpath d='M64 6.69a57.3 57.3 0 1 1 0 114.61A57.3 57.3 0 0 1 6.69 64' fill='none' stroke='%23404040' stroke-width='12'/%3E%3C/g%3E%3C/svg%3E");background-repeat:no-repeat;background-position:center center;background-color:transparent;background-size:min(2.5rem,calc(100% - .5rem))}.mt-footer{display:flex;flex-flow:wrap;margin:auto auto 2rem auto;padding:0 1.5rem;gap:1.5rem;align-items:center;justify-content:center}.visually-hidden{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}
\ No newline at end of file
diff --git a/dist/mastodon-timeline.umd.js b/dist/mastodon-timeline.umd.js
index 1f43f1b..12db65f 100644
--- a/dist/mastodon-timeline.umd.js
+++ b/dist/mastodon-timeline.umd.js
@@ -1,8 +1,8 @@
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).MastodonTimeline={})}(this,(function(t){"use strict";
-/**
- * Mastodon embed timeline
- * @author idotj
- * @version 4.2.1
- * @url https://gitlab.com/idotj/mastodon-embed-timeline
- * @license GNU AGPLv3
- */t.Init=class{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hideVideoPreview:!1,hidePreviewLink:!1,hideEmojos:!1,markdownBlockquote:!1,hideCounterBar:!1,txtMaxLines:"0",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",btnShowContent:"SHOW CONTENT",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#t((()=>{this.#e()}))}#t(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#e(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#i("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),s=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};s()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#t((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",''),this.#i("updateTimeline")}))}mtColorTheme(t){this.#t((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#a(){return new Promise(((t,e)=>{let s={};this.mtSettings.instanceUrl?"profile"===this.mtSettings.timelineType?this.mtSettings.userId?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your userId value","â ī¸"):"hashtag"===this.mtSettings.timelineType?this.mtSettings.hashtagName?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your hashtagName value","â ī¸"):"local"===this.mtSettings.timelineType?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your timelineType value","â ī¸"):this.#o("Please check your instanceUrl value","â ī¸"),this.mtSettings.hideEmojos||(s.emojos=this.mtSettings.instanceUrl+"/api/v1/custom_emojis");const i=Object.entries(s).map((([t,s])=>async function(t){const e=await fetch(t);if(!e.ok)throw new Error("Failed to fetch the following Url: "+t+"Error status: "+e.status+"Error message: "+e.statusText);return await e.json()}(s).then((e=>({[t]:e}))).catch((i=>(e(new Error("Something went wrong fetching data from: "+s)),this.#o(i.message),{[t]:[]})))));Promise.all(i).then((e=>{this.mtSettings.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),t()}))}))}async#i(t){await this.#a(),this.mtBodyNode.replaceChildren();let e=0;for(let t in this.mtSettings.fetchedData.timeline)("public"==this.mtSettings.fetchedData.timeline[t].visibility||!this.mtSettings.hideUnlisted&&"unlisted"==this.mtSettings.fetchedData.timeline[t].visibility)&&(this.mtSettings.hideReblog&&this.mtSettings.fetchedData.timeline[t].reblog||this.mtSettings.hideReplies&&this.mtSettings.fetchedData.timeline[t].in_reply_to_id||eThis may be due to an incorrect configuration in the parameters or to filters applied (to hide certains type of posts)";this.#o(t,"đ")}else"newTimeline"===t?(this.#r(),this.#l(),this.#m()):"updateTimeline"===t?this.#r():this.#o("The function buildTimeline() was expecting a param")}#n(t,e){this.mtBodyNode.insertAdjacentHTML("beforeend",this.#d(t,e))}#d(t,e){let s,i,a,o,n,r,l,m,d;t.reblog?(o=t.reblog.url,s='
";let g=[];if(t.media_attachments.length>0)for(let e in t.media_attachments)g.push(this.#u(t.media_attachments[e],t.sensitive));if(t.reblog&&t.reblog.media_attachments.length>0)for(let e in t.reblog.media_attachments)g.push(this.#u(t.reblog.media_attachments[e],t.reblog.sensitive));let u="";!this.mtSettings.hidePreviewLink&&t.card&&(u=this.#v(t.card));let v="";if(t.poll){let e="";for(let s in t.poll.options)e+="
",this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}}));
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).MastodonTimeline={})}(this,(function(t){"use strict";
+/**
+ * Mastodon embed timeline
+ * @author idotj
+ * @version 4.3.1
+ * @url https://gitlab.com/idotj/mastodon-embed-timeline
+ * @license GNU AGPLv3
+ */t.Init=class{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",dateLocale:"en-GB",dateOptions:{day:"2-digit",month:"short",year:"numeric"},hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hidePinnedPosts:!1,hideUserAccount:!1,hideEmojos:!1,hideVideoPreview:!1,hidePreviewLink:!1,hideCounterBar:!1,markdownBlockquote:!1,txtMaxLines:"0",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",btnShowContent:"SHOW CONTENT",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#t((()=>{this.#e()}))}#t(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#e(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#i("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),s=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};s()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#t((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",''),this.#i("updateTimeline")}))}mtColorTheme(t){this.#t((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#a(){return new Promise(((t,e)=>{let s={};this.mtSettings.instanceUrl?"profile"===this.mtSettings.timelineType?this.mtSettings.userId?(s.timeline=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`,this.mtSettings.hidePinnedPosts||(s.pinned=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?pinned=true`)):this.#o("Please check your userId value","â ī¸"):"hashtag"===this.mtSettings.timelineType?this.mtSettings.hashtagName?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your hashtagName value","â ī¸"):"local"===this.mtSettings.timelineType?s.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`:this.#o("Please check your timelineType value","â ī¸"):this.#o("Please check your instanceUrl value","â ī¸"),this.mtSettings.hideEmojos||(s.emojos=this.mtSettings.instanceUrl+"/api/v1/custom_emojis");const i=Object.entries(s).map((([t,s])=>async function(t){const e=await fetch(t);if(!e.ok)throw new Error("Failed to fetch the following Url: "+t+"Error status: "+e.status+"Error message: "+e.statusText);return await e.json()}(s).then((e=>({[t]:e}))).catch((i=>(e(new Error("Something went wrong fetching data from: "+s)),this.#o(i.message),{[t]:[]})))));Promise.all(i).then((e=>{this.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),t()}))}))}async#i(t){let e;if(await this.#a(),this.mtSettings.hidePinnedPosts||void 0===this.fetchedData.pinned?.length||0===this.fetchedData.pinned.length)e=this.fetchedData.timeline;else{e=[...this.fetchedData.pinned.map((t=>({...t,pinned:!0}))),...this.fetchedData.timeline]}this.mtBodyNode.replaceChildren();let s=0;for(let t in e)("public"==e[t].visibility||!this.mtSettings.hideUnlisted&&"unlisted"==e[t].visibility)&&(this.mtSettings.hideReblog&&e[t].reblog||this.mtSettings.hideReplies&&e[t].in_reply_to_id||sThis may be due to an incorrect configuration in the parameters or to filters applied (to hide certains type of posts)";this.#o(t,"đ")}else"newTimeline"===t?(this.#r(),this.#l(),this.#m()):"updateTimeline"===t?this.#r():this.#o("The function buildTimeline() was expecting a param")}#n(t,e){this.mtBodyNode.insertAdjacentHTML("beforeend",this.#d(t,e))}#d(t,e){let s,i,a,o,n,r,l,m,d,h;t.reblog?(n=t.reblog.url,s='
";let u=[];if(t.media_attachments.length>0)for(let e in t.media_attachments)u.push(this.#u(t.media_attachments[e],t.sensitive));if(t.reblog&&t.reblog.media_attachments.length>0)for(let e in t.reblog.media_attachments)u.push(this.#u(t.reblog.media_attachments[e],t.reblog.sensitive));let v="";!this.mtSettings.hidePreviewLink&&t.card&&(v=this.#v(t.card));let b="";if(t.poll){let e="";for(let s in t.poll.options)e+="
",this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}}));
diff --git a/examples/hashtag-timeline.html b/examples/hashtag-timeline.html
index 7c5aa03..83511fe 100644
--- a/examples/hashtag-timeline.html
+++ b/examples/hashtag-timeline.html
@@ -67,7 +67,7 @@
đ Mastodon embed timeline
-
Profile timeline
+
Hashtag timeline
This example shows posts containing the hashtag
diff --git a/examples/local-timeline-customized.html b/examples/local-timeline-customized.html
new file mode 100644
index 0000000..d9f8f43
--- /dev/null
+++ b/examples/local-timeline-customized.html
@@ -0,0 +1,169 @@
+
+
+
+
+ Mastodon embed timeline
+
+
+
+
+
+
+
+
+
+
+
+
+
+
đ Mastodon embed timeline
+
Local timeline (customized)
+
+ This example shows 10 posts from the following instance:
+
+ mastodon.social
+
+
+ Contains several CSS styles that change its appearance without the
+ need to modify the original CSS file (inspect the code at the
+ beginning of the HTML file to see the changes).
+
+
+ At JS level, it defaults to the light theme and the date is displayed
+ in US format using digits only. In order to achieve a minimalist
+ style, the following options have been changed at its
+ initialization:
+