Comments Widget
The Comments widget is a component that displays a stream of comments. It supports rendering in different styles and can display plain text or markdown formatted messages. The widget is capable of rendering existing comments and allows for adding, deleting, or editing previously created comments. It operates entirely on the client-side and can be integrated with any backend service.
This widget is licensed under the MIT license.
Quick start
First steps
To start with the widget, add the necessary package to your project first.
npm install wx-svelte-core
npm install wx-svelte-comments
or
yarn add wx-svelte-core
yarn add wx-svelte-comments
Now, import the widget into your project.
<script>
import { Willow } from 'wx-svelte-core';
import { Comments } from 'wx-svelte-comments';
</script>
<Willow>
<Comments />
</Willow>
The Willow
component is a default theme wrapper that adds necessary styles for all SVAR widgets. The Comments
component can function without it, but it will lack styles and require additional styling effort. It is recommended to add the Willow
tag once at the top level of your application.
Full init code
To see the widget in action, add some comments to the widget.
<script>
import { Comments } from 'wx-svelte-comments';
const value = [
{
id: "1",
content: "Hello, world!",
user: 1,
date: new Date(),
},
];
const users = [
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Doe" },
];
</script>
<Comments {value} {users} />
Visual Themes
The widget is provided in two visual styles - Light and Dark, controlled by the theme tag.
<script>
import { Willow, WillowDark } from "wx-svelte-core";
</script>
<!-- Light -->
<Willow>
<Comments />
</Willow>
<!-- Dark -->
<WillowDark>
<Comments />
</WillowDark>
Initialization
The widget provides several methods to initialize and load comments. It supports fetching comments from a backend API, rendering an empty widget, or initializing with predefined data and user information. These options allow flexibility in integrating the widget into different applications and use cases.
Initializing the Widget and Loading Comments
<script>
import { Comments } from 'wx-svelte-comments';
let value = [];
fetch('/api/comments')
.then(r => r.json())
.then(x => value = x);
</script>
{#await value}
<Comments {value} />
{/await}
This approach initializes the widget by fetching comment data from a backend API. It is suitable when the comments are stored on a server and need to be loaded dynamically. The fetch
function retrieves the comments in JSON format, which is then passed to the Comments
component. The await
block ensures the comments are displayed only after the data is successfully loaded.
Initializing an Empty Comments Widget
<script>
import { Comments } from 'wx-svelte-comments';
</script>
<Comments />
This method initializes the widget without any preloaded comments. It is useful when the application starts with no existing comments, allowing users to add new comments from scratch. The component renders a clean interface with no prefilled data.
Initializing the Widget with Data and a List of Users
<script>
import { Comments } from 'wx-svelte-comments';
const value = [
{
id: "1",
content: "Hello, world!",
user: 1,
date: new Date(),
},
];
const users = [
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Doe" },
];
</script>
<Comments {value} {users} />
This option initializes the widget with predefined comments and a list of users. Each comment references a user by their ID, and the users
array provides the user details. This setup is ideal when the application needs to display comments along with user information, such as names, but the user data is managed separately from the comment data.
Initializing the Widget with Data and Embedded Authors
<script>
import { Comments } from 'wx-svelte-comments';
const value = [
{
id: "1",
content: "Hello, world!",
author:{ id: 1, name: "John Doe" },
date: new Date(),
},
];
</script>
<Comments {value} />
This method initializes the widget with predefined comments where the author information is embedded directly within each comment. It is suitable when the application has a compact data structure where user details are stored as part of the comment object. This approach simplifies the data model by combining comments and author details into a single structure.
User Interaction
The widget includes methods to handle user comments and interactions. It enables functionalities like defining the current user, auto-focusing the comments editor, tracking changes in data, and retrieving the list of comments.
Defining the Current User
The widget allows specifying the currently active user. This is useful for scenarios where specific user comments need to be highlighted or given special permissions, such as editing or deleting. Comments from the active user can have distinct styling for better visual differentiation.
<script>
import { Comments } from 'wx-svelte-comments';
const users = [
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Doe" },
];
</script>
<Comments {value} {users} activeUser={1} />
In this example, the activeUser
property is set to 1
, indicating that the user with id: 1
is the current user. Their comments can be edited or deleted through the UI and can have separate styling applied to them.
Auto-Focusing the Comments Editor
The widget provides the ability to automatically focus the comments editor when it is rendered. This is particularly useful for use-cases where the widget is integrated into a page that prioritizes user input, such as a discussion forum or a feedback form.
<script>
import { Comments } from 'wx-svelte-comments';
</script>
<Comments focus={true} />
By setting the focus
property to true
, the input field for adding a comment will be automatically focused after the widget is rendered.
Tracking Data Changes
The widget supports monitoring changes to the comments data. It provides detailed information about the type of change (add, update, or delete), the specific comment affected, and the state of the data before and after the change. This functionality is essential for implementing features like real-time updates, logging, or syncing with a backend.
interface OnChange {
// kind of change
action: "add" | "update" | "delete";
// id of changed comment
id?: number;
// changed comment
comment?: Comment;
// current comments data
data: Comment[];
// original comments data
originalValue: Comment[] | number | string;
}
<script>
import { Comments } from 'wx-svelte-comments';
import { value } from './data.js';
const onchange = ({ id, action, comment, originalValue }) => {
console.log(id, action, comment, originalValue);
};
</script>
<Comments {value} {onchange} />
For "add" operations, the OnChange
handler does not provide an id
, as the comment may not yet have a unique identifier. For "delete" operations, the comment
object is not included, as the comment has already been removed from the data. The originalValue
property represents the initial state of the data when the widget was loaded, which could either be a comment stream's ID or the array of comments.
Retrieving the List of Comments
The widget allows binding the comments data to a variable, making it possible to access the current state of the comments directly from the component. This is useful for scenarios where the comments need to be further processed or sent to a backend.
<script>
import { Comments } from 'wx-svelte-comments';
// will contain the current comments array
let data = [];
</script>
<Comments bind:value={data} />
In this example, the value
property of the widget is bound to the data
variable. This ensures that data
always holds the latest array of comments, reflecting any changes made within the widget.
Comment Rendering
The widget provides multiple options for rendering comments. It supports rendering plain text, markdown, or custom formatted content. Comments can be displayed in different layouts, such as a text chat, a forum thread, or using custom components. Additional features include setting a custom date format and enabling a readonly mode for viewing comments without interaction.
Rendering Content in a Custom Format
<script>
import { Comments } from 'wx-svelte-comments';
const value = [
{
id: "1",
content: "Hello @[John](user:1), check this link: {link|https://example.com|Click here}",
date: new Date()
}
];
// Custom formatter that handles @mentions and custom link syntax
const customFormat = (text) => {
// Convert @mentions: @[Name](user:id) -> <a href="/users/id">Name</a>
return text.replace(/@\[(.*?)\]\(user:(\d+)\)/g,
'<a href="/users/$2">$1</a>');
};
</script>
<Comments {value} format={customFormat} />
This setup is used when specific formatting rules are required for the content. The customFormat
function processes the text, replacing patterns like mentions or custom links with HTML markup. This is useful for applications where dynamic user mentions or custom link handling is needed.
Rendering Content in Markdown Format
<script>
import { Comments } from 'wx-svelte-comments';
const value = [
{
id: "1",
content: "Hello, **world**",
author:{ id: 1, name: "John Doe" },
date: new Date(),
},
];
</script>
<Comments {value} format="markdown" />
This configuration is suitable for content that includes markdown syntax. The widget automatically converts markdown elements like bold, italics, or lists into their respective rendered HTML. Use this when users submit comments in markdown format.
Rendering Content as Plain Text
<script>
import { Comments } from 'wx-svelte-comments';
const value = [
{
id: "1",
content: "Hello, world!",
author:{ id: 1, name: "John Doe" },
date: new Date(),
},
];
</script>
<Comments {value} format="text" />
This option is designed for cases where the content should be displayed as plain text. No formatting or special syntax is applied, making it suitable for simple comments without any additional styling or processing.
Rendering Messages as a Text Chat
<script>
import { Comments } from 'wx-svelte-comments';
import { value } from './data.js';
</script>
<Comments {value} render="bubbles" />
This layout is ideal for rendering comments in a chat-style interface. Messages are displayed as bubbles, providing a modern, conversational look. Use this for applications that aim to replicate a chat or messaging experience.
Rendering Messages with a Custom Component
<script>
import { Comments } from 'wx-svelte-comments';
import { MyMessageRenderer } from './MyMessageRenderer.svelte';
import { value } from './data.js';
</script>
<Comments {value} render={MyMessageRenderer} />
This configuration allows for complete customization of how messages are displayed. By passing a custom Svelte component, developers can define unique layouts or styles for each comment. This is useful for highly customized interfaces that require specific visual designs.
Rendering Messages as a Forum Thread
<script>
import { Comments } from 'wx-svelte-comments';
import { value } from './data.js';
</script>
<Comments {value} render="flow" />
This option is designed for displaying comments in a forum thread style. Messages are shown in a linear or hierarchical flow, making it suitable for discussions with replies and nested comments.
Setting the Date Format for Messages
<script>
import { Locale } from "wx-svelte-core";
import { Comments } from "wx-svelte-comments";
const myLang = {
dateFormat: "%j. %F %Y %H:%i",
};
</script>
<Locale words={{ comments:myLang }}>
<Comments />
</Locale>
This feature allows customization of how dates are displayed in comments. By providing a specific date format, developers can ensure consistency with the application's locale or user preferences.
Displaying the Widget in Readonly Mode
<script>
import { Comments } from 'wx-svelte-comments';
import { value } from './data.js';
</script>
<Comments {value} readonly={true} />
This mode is used when comments should only be viewed but not interacted with. It disables editing, deleting, or adding new comments. This is helpful for scenarios where comments are archived or when users have read-only permissions.
Data Management
The widget provides robust support for managing comments data through various methods. Developers can load, save, and manage comments using REST API helpers, local storage, and other custom data sources. These methods cater to different use cases, such as fetching comments, persisting changes, or converting identifiers into data.
Loading and Saving Comments via REST API
This example demonstrates how to use a REST API helper to load and save comments. The RestURL
utility is utilized to fetch data and handle changes to comments.
<script>
import { RestURL } from "wx-lib-data-provider";
import { Comments } from 'wx-svelte-comments';
const url = new RestURL("https://some.com/api/comments");
</script>
<Comments
ondata={v => url.get(v)}
onchange={({ action, comment, id, originalValue: v }) =>
url.path(v).save(action, comment, id)}
/>
In this configuration:
ondata
fetches the comments data from the specified REST API endpoint using theget
method.onchange
handles any changes to the comments, such as adding, editing, or deleting. Thesave
method sends the updated data back to the API.- The
RestURL
utility simplifies the interaction with RESTful endpoints.
This setup is ideal for projects where comments are managed on a backend server with a REST API.
Saving Changes to Comments Using Local Storage
This example illustrates how to store and retrieve comments data locally using the browser's local storage.
<script>
import { RestURL } from "wx-lib-data-provider";
import { Comments } from 'wx-svelte-comments';
const url = new RestURL("https://some.com/api/comments");
</script>
<Comments
value={1}
ondata={v => localStorage.getItem(`comments-${v}`)}
onchange={({ value }) =>
localStorage.setItem(`comments-${value}`, JSON.stringify(value))}
/>
Key details:
ondata
retrieves comments from local storage using a unique key associated with the comment stream.onchange
saves the updated comments back into local storage.- The
value
attribute is used as an identifier for the comment stream.
This configuration is useful for offline-first applications or scenarios where comments need to be temporarily stored on the client-side.
Loading Comments via REST API
This example focuses on fetching comments data from a REST API without handling changes.
<script>
import { RestURL } from "wx-lib-data-provider";
import { Comments } from 'wx-svelte-comments';
const url = new RestURL("https://some.com/api/comments");
</script>
<Comments ondata={v => url.get(v)} />
Details:
ondata
fetches the comments data using theget
method of theRestURL
utility.- This setup is suitable for read-only scenarios where comments need to be displayed but not modified.
Converting Comment Stream ID to Data
This example demonstrates how to map a comment stream identifier to its associated data using a custom fetch implementation.
<script>
import { Comments } from 'wx-svelte-comments';
const ondata = (v) => {
return fetch(`/api/comments/${v}`).then(r => r.json());
};
</script>
<Comments value={1} {ondata} />
Key points:
ondata
uses thefetch
API to retrieve comments data from a backend endpoint. The ID of the comment stream is dynamically included in the URL.- The
fetch
call returns a promise that resolves to the comments data.
This approach is flexible and can be adapted for projects with custom backend APIs. The ondata
function must return either a data array or a promise resolving to a data array.
Localization
The widget supports localization, enabling it to be displayed in different languages. This is particularly useful for applications targeting users from various linguistic backgrounds. Developers can define custom translations for specific widget terms and phrases.
Localizing the Widget to Another Language
<script>
import { Locale } from "wx-svelte-core";
import { Comments } from "wx-svelte-comments";
const myLang = {
Add: "Ajouter",
Edit: "Modifier",
Delete: "Supprimer",
Unknown: "Inconnu",
Me: "Moi",
"Add a comment...": "Ajouter un commentaire..."
};
</script>
<Locale words={{ comments:myLang }}>
<Comments />
</Locale>
This example demonstrates how the widget can be localized to French. The myLang
constant defines the translations for specific terms used within the widget, such as "Add," "Edit," and "Delete." The Locale
component is used to apply these translations by wrapping the Comments
widget.
When applied, the widget interface will display the provided French terms instead of the default ones. This ensures a seamless user experience for French-speaking users. It is critical to ensure all necessary terms are translated to avoid displaying untranslated or default text.