A flexible, extensible tip-of-the-day system with support for multiple collections, output formats, and delivery methods.
- 📚 Multiple Collections: Combine tips from different sources
- 🎨 Multiple Output Formats: HTML, Markdown, and styled terminal output
- 🎲 Random Selection: Get a different tip each time
- 🔧 Extensible Architecture: Easy to add new loaders, selectors, and formatters
- 🌐 CLI and Web: Use from command line or deploy as a web app
- 🧪 Well-Tested: Comprehensive test coverage with clean architecture
npm install
npm run buildDisplay a random tip from a single collection:
npm run daily-tip leadership-toneDisplay a random tip from multiple collections:
npm run daily-tip leadership-tone productivity-hacksOr use the convenience scripts:
npm run daily-tip:leadership # Leadership tips only
npm run daily-tip:productivity # Productivity tips only
npm run daily-tip:all # All collections combinedBuild and serve the web version:
npm run build:web
npm run serveThen open your browser to:
http://localhost:8080- Select a collectionhttp://localhost:8080?type=leadership-tone- Specific collectionhttp://localhost:8080?type=leadership-tone,productivity-hacks- Multiple collections
daily-tip/
├── src/
│ ├── loaders/ # Load tips from various sources
│ ├── selectors/ # Select which tip to display
│ ├── formatters/ # Format tips for different outputs
│ ├── orchestrator/ # Coordinate the tip generation process
│ ├── bin/ # CLI entry points
│ └── web/ # Web application
├── collections/ # Tip collections (JSON files)
├── docs/ # Documentation
└── dist/ # Built output
# Single collection
node dist/bin/daily-tip.js leadership-tone
# Multiple collections (shows collection name with each tip)
node dist/bin/daily-tip.js leadership-tone productivity-hacks
# Help
node dist/bin/daily-tip.js --helpimport DailyTipBuilder from './src/index';
import { JsonTipLoader } from './src/loaders/json-tip-loader';
import RandomTipSelector from './src/selectors/random-tip';
import { HtmlTipFormatter } from './src/formatters/html-formatter';
import DefaultTipOrchestrator from './src/orchestrator/default';
// Build the tip system
const orchestrator = new DailyTipBuilder<string>()
.withLoader(new JsonTipLoader('./collections/leadership-tone.json'))
.withSelector(new RandomTipSelector())
.withFormatter(new HtmlTipFormatter())
.withOrchestrator(DefaultTipOrchestrator)
.build();
// Get a tip
const tip = orchestrator.getTip();
console.log(tip);import { CompositeTipLoader } from './src/loaders/composite-loader';
const loader = new CompositeTipLoader([
new JsonTipLoader('./collections/leadership-tone.json'),
new JsonTipLoader('./collections/productivity-hacks.json'),
]);
const orchestrator = new DailyTipBuilder<string>()
.withLoader(loader)
.withSelector(new RandomTipSelector())
.withFormatter(new ShellTipFormatter())
.withOrchestrator(DefaultTipOrchestrator)
.build();
const tip = orchestrator.getTip();Create a JSON file in the collections/ directory:
{
"title": "My Tips",
"tips": [
{
"title": "First Tip",
"tip": "This is the content of the first tip. You can use **markdown** formatting."
},
{
"title": "Second Tip",
"tip": "This is another tip with a list:\n- Item 1\n- Item 2\n- Item 3"
}
]
}Then use it:
npm run daily-tip my-tipsCreate a class that implements the TipLoader interface:
import { TipLoader, Tip } from './src/loaders';
export class ApiTipLoader implements TipLoader {
constructor(private apiUrl: string) {}
getTips(): Tip[] {
// Fetch tips from API
const response = fetch(this.apiUrl);
return response.json();
}
getCollectionTitle(): string {
return "API Tips";
}
}Create a class that implements the TipFormatter<T> interface:
import { TipFormatter } from './src/formatters';
import { Tip } from './src/loaders';
export class JsonTipFormatter implements TipFormatter<string> {
formatTip(tip: Tip, categoryTitle?: string): string {
return JSON.stringify({ tip, categoryTitle }, null, 2);
}
}Create a class that implements the TipSelector interface:
import { TipSelector } from './src/selectors';
import { Tip } from './src/loaders';
export class SequentialTipSelector implements TipSelector {
private index = 0;
getTip(tips: Tip[]): Tip {
const tip = tips[this.index];
this.index = (this.index + 1) % tips.length;
return tip;
}
}npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage reportnpm run build # Full build (compile + web)
npm run build:compile # TypeScript compilation only
npm run build:web # Web bundle onlynpm run lint # Check for linting issues
npm run lint:fix # Fix linting issues
npm run format # Format code with Prettier
npm run format:check # Check formatting- Make changes to source files in
src/ - Run tests:
npm test - Build:
npm run build - Test CLI:
npm run daily-tip - Test web:
npm run serve
The system follows SOLID principles and uses several design patterns:
- Strategy Pattern: Interchangeable loaders, selectors, and formatters
- Composite Pattern: Combine multiple loaders into one
- Builder Pattern: Fluent API for constructing the tip system
- Dependency Injection: Components receive dependencies through constructors
For detailed architecture documentation, see development/architecture.html.
After building, you can view the complete API documentation:
npm run build # Generates docs in dist/public/docs/
npm run docs:serve # Serves docs at http://localhost:8081Or generate docs separately:
npm run docs # Generate API docs and convert development docs to HTMLThe documentation includes:
- API Documentation: TypeDoc-generated API reference at
/docs/index.html - Development Documentation: Converted markdown docs at
/docs/development/
- Leadership Tone: Tips for effective leadership communication
- Productivity Hacks: Practical productivity techniques
| Script | Description |
|---|---|
npm run build |
Full build (compile + web) |
npm run build:compile |
Compile TypeScript |
npm run build:web |
Build web bundle |
npm test |
Run all tests |
npm run test:watch |
Run tests in watch mode |
npm run test:coverage |
Run tests with coverage |
npm run lint |
Check linting |
npm run lint:fix |
Fix linting issues |
npm run format |
Format code |
npm run daily-tip |
Run CLI (requires args) |
npm run daily-tip:leadership |
Leadership tips |
npm run daily-tip:productivity |
Productivity tips |
npm run daily-tip:all |
All collections |
npm run serve |
Serve web app |
npm run docs |
Generate API documentation |
npm run docs:serve |
Serve API docs at port 8081 |
- Node.js 18+ (recommended)
- npm 10+
ISC
Contributions are welcome! Please read the Contributing Guide for details on our code of conduct and the process for submitting pull requests.
- Start Simple: Begin with a single collection and the CLI
- Explore Collections: Try different collections to see the variety
- Combine Collections: Use multiple collections for diverse tips
- Extend It: Add your own loaders, selectors, or formatters
- Read the Docs: Check out the architecture and design pattern docs
If you encounter build errors:
npm run clean
npm install
npm run buildIf tests fail:
npm run test:coverageCheck the coverage report to identify issues.
Make sure you've built the web bundle:
npm run build:web
npm run serveFor issues, questions, or contributions, please refer to the Contributing Guide.