Skip to content

Commit

Permalink
improved the configuration handling
Browse files Browse the repository at this point in the history
  • Loading branch information
hasith committed Sep 8, 2024
1 parent f345900 commit 28425ab
Show file tree
Hide file tree
Showing 20 changed files with 336 additions and 150 deletions.
159 changes: 159 additions & 0 deletions docs/plugin-development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
---
title: Installation
layout: home
nav_order: 5
---

# Plugin Development

Plugins are the building blocks of ProductLed. They are responsible for creating interactive effects on web pages to guide users through the product experience. Plugins can be used to highlight specific elements, display tooltips, show modals, and more.

## Plugin Structure

To get started, create a new folder in packages/@productled folder with the name of the plugin.

Now create a file called `package.json` with the following content:

```json
{
"name": "@productled/tooltips",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",

"scripts": {
"build": "tsc",
"test": "jest",
"clean": "rm -rf dist"
},
"dependencies": {

},
"devDependencies": {
"@types/node": "^20.14.9",
"ts-node": "^10.9.2",
"typescript": "^4.9.5"
}
}
```

Create a `tsconfig.json` file with the following content:

```json
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"lib": ["ESNext", "DOM"],
"module": "ESNext",
"target": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"declaration": true, // set to true on prod
"sourceMap": true, // set to true on dev
"strict": true,
"types": ["node"]
},
"include": ["src/**/*"]
}
```

### Create the Source Files

Create a `src` folder and add an `index.ts` and `pluginClass.ts` file with the following content:

`index.ts`

```typescript
export { default as PluginClass } from './PluginClass';
```

`PluginClass.ts`

```typescript
import { Plugin } from '@productled/core';

export class PluginClass implements Plugin {
private key: string = "plugin-name";

get Name(): string {
return this.key;
}

create(element: HTMLElement, conf: any, theme: Theme): void {
if (element) {
// Apply the plugin effect on the specified HTML element
}
}

removeAll(): void {
const spotlights = document.querySelectorAll('.productled-' + this.key);
spotlights.forEach(spotlight => {
spotlight.remove();
});
}
}
```

### The `create` Method

```typescript
create(element: HTMLElement, conf: any, theme: Theme): void {
if (element) {
// Apply the plugin effect on the specified HTML element
}
}
```

The `create` method takes three parameters: `element`, `conf`, and `theme`. Here's what each parameter represents:

- **`element`** is of type `HTMLElement`. It represents the HTML element on which the plugin will create the effect.
- **`conf`** is of type `any`. It represents the configuration object that contains properties specified in the `productled-config.json` file. These properties will be used to customize the effect created by the plugin.
- **`theme`** is of type `Theme`. It represents the theme object that will be used to style the effect created by the plugin.

In summary, the `create` method is responsible for creating an effect on a specified HTML element. It uses the provided configuration and theme to customize the spotlight's appearance and behavior.

### The `removeAll` Method

This method removes all the plugin instances created by the plugin. It selects all elements with the class `productled-pluginName` (where `pluginName` is the key of the plugin) and removes them from the DOM.

### The `Name` Property

The `Name` property is a getter method that returns the key of the plugin. This key is used to identify the plugin and differentiate it from other plugins. In this case, the key is set to `"plugin-name"`.

## Registering the Plugin

To register the plugin with the ProductLed library, you need to add it to the `productled-config.json` file in your project. Here's an example of how you can add the plugin to the configuration file:

```json
{
"hooks": [
{
"plugin": "plugin-name",
"trigger": {
"url": "/page/subpage*",
"selector": ".spot-me",

"frequency": "always",
"schedule": {
"start": { "year": "2024","month": "04", "date": "01", "time": "09:00" },
"end": { "year": "2024", "month": "12", "date": "01", "time": "09:00" }
}
},
"config": {
"title": "Plugin Title",
"description": "Plugin Description",
"link": "https://plugin-link.com",
"positioning": {
"alignment": "right-center",
"left": "60",
"top": "10"
}
}
}
]
}
```

You may use the sample projects in the `packages/samples` folder to test your plugin.
65 changes: 29 additions & 36 deletions docs/plugins/spotlights.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Once the core library is installed, you can install the Spotlights plugin using
```bash
npm install @productled/spotlights
```

Now, you need to register the Spotlights plugin with the Productled core at the start of your application. This can be done in your main application file (e.g., `index.tsx`):

```typescript
Expand All @@ -40,51 +41,43 @@ After installing the Spotlights plugin, you need to configure it within your `pr

Below is an example configuration for a spotlight:

File: `src/productled-conf.json`
Example File: `src/productled-conf.json`

```json
{
"spotlights": [{
"title": "New Click Me Feature",
"description": "You can now send emails directly from here",
"link": "http://myblog.com/new_feature_intro",

"trigger": {
"url": "/page/subpage",
"selector": ".spot-me",

"frequency": "always",
"schedule": {
"start": { "year": "2024", "month": "04", "date": "01", "time": "09:00" },
"end": { "year": "2024", "month": "12", "date": "01", "time": "09:00" }
"hooks": [
{
"plugin": "spotlight",
"trigger": {
"url": "/page/subpage*",
"selector": ".spot-me",

"frequency": "always",
"schedule": {
"start": { "year": "2024","month": "04", "date": "01", "time": "09:00" },
"end": { "year": "2024", "month": "12", "date": "01", "time": "09:00" }
}
},
"config": {
"title": "New Feature",
"description": "Just release today. Click me to learn more.",
"link": "https://plugin-link.com",
"positioning": {
"left": "60",
"top": "10"
}
}
},
"positioning": {
"alignment": "right-center",
"left": "75",
"top": "15"
}
}]
]
}
```

Explanation of Configuration:
- `title`: The title of the spotlight. In this example, it's "New Click Me Feature".
- `description`: A brief description of what the spotlight is highlighting. Here, it's "You can now send emails directly from here".
- `link`: A URL that users can follow to learn more about the feature. This could link to a blog post, documentation, or a tutorial. In this example, the link is "http://myblog.com/new_feature_intro".

Trigger Configuration:
- `url`: The specific URL or route where the spotlight should appear. Here, the spotlight is triggered on "/page/subpage".
- `selector`: The CSS selector of the element that the spotlight will highlight. In this example, it targets the element with the class "spot-me".
- `frequency`: Determines how often the spotlight should be shown. Possible values include "always", "once", "daily", etc. Here, it is set to "always".
- `schedule`: Defines the time window during which the spotlight should be active.
- `start`: The start date and time for the spotlight. In this example, it starts on April 1, 2024, at 09:00.
- `end`: The end date and time for the spotlight. In this example, it ends on December 1, 2024, at 09:00.

Positioning Configuration:
- `alignment`: Specifies the alignment of the spotlight relative to the selected element. Here, it's set to "right-center".
- `left`: The distance from the left edge of the viewport or element. In this example, it’s set to "75".
- `top`: The distance from the top edge of the viewport or element. In this example, it’s set to "15".
In this example, the spotlight will be displayed on the URL `/page/subpage*` whenever an element with the class `.spot-me` is present. The spotlight will have a title, description, and a link to learn more about the feature. The spotlight will be positioned at `left: 60` and `top: 10` on the screen.

- **`plugin`**: The key of the plugin, which is set to `"spotlight"`.
- **`trigger`**: The trigger object that defines when the spotlight should be displayed. It includes the URL pattern, selector, frequency, and schedule.
- **`config`**: The configuration object that defines the spotlight's title, description, link, and positioning.

## Using the Spotlight

Expand Down
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 20 additions & 4 deletions packages/@productled/core/src/ConfigStore.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
import { Config, Hook } from "./hooks/Hook";

class ConfigStore {
private config: any;
private pluginDict: { [plugin: string]: Hook[] } = {};


public set Configuration(config: any) {
this.config = config;
public load(config: Config) {
this.addToPluginDictionary(config);
}

public getHooks(pluginName: string): any {
return this.config[pluginName] ?? [];
return this.pluginDict[pluginName] || [];
}

private addToPluginDictionary(hooksConfig: Config): { [plugin: string]: Hook[] } {

hooksConfig.hooks.forEach(hook => {
if (!this.pluginDict[hook.plugin]) {
this.pluginDict[hook.plugin] = [];
}
this.pluginDict[hook.plugin].push(hook);
});

return this.pluginDict;
}


}

export default ConfigStore;
4 changes: 2 additions & 2 deletions packages/@productled/core/src/Productled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class Productled {
this.hookStore = new HookStore();
this.pluginStore = new PluginStore();
this.documentService = new DocumentService();
this.configStore = new ConfigStore();
this.routeListener = new RouteListener();
this.themeManager = new ThemeManager();
this.configStore = new ConfigStore();
this.routeListener.addListener(this.routeChanged.bind(this));
}

Expand Down Expand Up @@ -61,7 +61,7 @@ class Productled {
* This method registers the hook configuration with the Productled instance.
*/
public loadConfig(config: any) {
this.configStore.Configuration = config;
this.configStore.load(config);
}

/**
Expand Down
60 changes: 19 additions & 41 deletions packages/@productled/core/src/hooks/Hook.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
interface HookTrigger {
url: string;
selector: string;
frequency: 'always' | 'once'; // You can add more frequency types if needed
schedule?: Schedule;
}

interface Hook {
plugin: string;
trigger: HookTrigger;
config: any;
}

interface Config {
hooks: Hook[];
}


interface Schedule {
start: {
year: string;
Expand All @@ -13,44 +31,4 @@ interface Schedule {
};
}

class Trigger {
public url: string;
public selector: string;
public frequency: string;
public schedule: Schedule;

constructor(url: string, selector: string, frequency: string, schedule: Schedule) {
this.url = url;
this.selector = selector;
this.frequency = frequency;
this.schedule = schedule;
}

private parseDateTime(dateTime: { year: string; month: string; date: string; time: string }): Date {
const [hours, minutes] = dateTime.time.split(':').map(Number);
return new Date(
Number(dateTime.year),
Number(dateTime.month) - 1,
Number(dateTime.date),
hours,
minutes
);
}

public isWithinSchedule(): boolean {
const startDate = this.parseDateTime(this.schedule.start);
const endDate = this.parseDateTime(this.schedule.end);
const now = new Date();

return now >= startDate && now <= endDate;
}

}

interface Hook {
pluginName: string;
trigger: Trigger;
}


export { Trigger, Schedule, Hook as default };
export { HookTrigger, Schedule, Hook, Config };
Loading

0 comments on commit 28425ab

Please sign in to comment.