@magicpages/ghost-typesense-search-ui 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -43
- package/dist/search.min.css +1 -0
- package/dist/search.min.js +1 -1
- package/dist/search.min.js.map +1 -0
- package/package.json +2 -2
- package/dist/search.js +0 -24027
package/README.md
CHANGED
|
@@ -1,88 +1,115 @@
|
|
|
1
1
|
# @magicpages/ghost-typesense-search-ui
|
|
2
2
|
|
|
3
|
-
A beautiful, accessible search interface for Ghost blogs using Typesense.
|
|
3
|
+
A beautiful, accessible search interface for Ghost blogs using Typesense. This package provides a drop-in replacement for Ghost's default search functionality, offering enhanced features and seamless integration with Typesense.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🔍 Real-time search
|
|
9
|
+
- 🔍 Real-time search powered by Typesense (needs a Typesense server)
|
|
10
10
|
- 🎨 Beautiful, accessible interface
|
|
11
|
-
- 🌓 Automatic dark mode
|
|
11
|
+
- 🌓 Automatic dark mode support
|
|
12
12
|
- ⌨️ Full keyboard navigation
|
|
13
|
-
- 📱 Responsive design
|
|
14
|
-
- 🎯
|
|
13
|
+
- 📱 Responsive design for all devices
|
|
14
|
+
- 🎯 Configurable common searches suggestions
|
|
15
|
+
- ⚡ Lightweight and performant
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
There are two ways to integrate the search UI into your Ghost site:
|
|
20
|
+
|
|
21
|
+
### Option 1: Replace Ghost's Default Search (Recommended)
|
|
22
|
+
|
|
23
|
+
This is the preferred method as it prevents loading two search scripts, resulting in better performance. You'll need access to your Ghost configuration.
|
|
19
24
|
|
|
20
25
|
Add to your `config.[environment].json`:
|
|
21
26
|
```json
|
|
22
27
|
"sodoSearch": {
|
|
23
|
-
"url": "
|
|
28
|
+
"url": "https://unpkg.com/@magicpages/ghost-typesense-search-ui/dist/search.min.js"
|
|
24
29
|
}
|
|
25
30
|
```
|
|
26
31
|
|
|
27
|
-
Or set environment variable:
|
|
32
|
+
Or set the environment variable:
|
|
28
33
|
```bash
|
|
29
|
-
sodoSearch__url=
|
|
34
|
+
sodoSearch__url=https://unpkg.com/@magicpages/ghost-typesense-search-ui/dist/search.min.js
|
|
30
35
|
```
|
|
31
36
|
|
|
32
|
-
### Option 2:
|
|
37
|
+
### Option 2: Code Injection Method
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
If you're using a managed Ghost host like Ghost(Pro) where you can't modify the configuration, use this method. The script will automatically remove any traces of the default search to prevent conflicts, but cannot prevent the `sodo-search.min.js` from being loaded.
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
Add to your site's code injection (Settings → Code injection → Site Header):
|
|
37
42
|
|
|
43
|
+
```html
|
|
38
44
|
<script src="https://unpkg.com/@magicpages/ghost-typesense-search-ui/dist/search.min.js"></script>
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
For either method, you can also self-host the `search.min.js` and add that URL instead of `https://unpkg.com/@magicpages/ghost-typesense-search-ui/dist/search.min.js`.
|
|
42
48
|
|
|
43
49
|
## Configuration
|
|
44
50
|
|
|
51
|
+
Configure the search by adding a global configuration object before loading the script. You can add this to your theme, or use Ghost's code injection to add it to your site's header.
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<script>
|
|
55
|
+
window.__MP_SEARCH_CONFIG__ = {
|
|
56
|
+
typesenseNodes: [{
|
|
57
|
+
host: 'your-typesense-host',
|
|
58
|
+
port: '443',
|
|
59
|
+
protocol: 'https'
|
|
60
|
+
}], // also supports a Typesense cluster
|
|
61
|
+
typesenseApiKey: 'your-search-only-api-key', // Under no circumstances use an admin API key here. These values are stored client-side and are therefore accessible to the end user.
|
|
62
|
+
collectionName: 'your-collection-name',
|
|
63
|
+
theme: 'system', // 'light', 'dark', or 'system'
|
|
64
|
+
commonSearches: ['Getting Started', 'Tutorials', 'API'] // can also be empty
|
|
65
|
+
};
|
|
66
|
+
</script>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Configuration Options
|
|
70
|
+
|
|
45
71
|
| Option | Type | Required | Description |
|
|
46
72
|
|--------|------|----------|-------------|
|
|
47
|
-
| `typesenseNodes` | `Array` | Yes | Typesense node configurations |
|
|
48
|
-
| `typesenseApiKey` | `String` | Yes | Search-only API key |
|
|
49
|
-
| `collectionName` | `String` | Yes |
|
|
50
|
-
| `theme` | `String` | No | 'light', 'dark', or 'system' |
|
|
51
|
-
| `commonSearches` | `Array` | No |
|
|
52
|
-
| `searchFields` | `Object` | No |
|
|
73
|
+
| `typesenseNodes` | `Array` | Yes | Array of Typesense node configurations |
|
|
74
|
+
| `typesenseApiKey` | `String` | Yes | Search-only API key from Typesense |
|
|
75
|
+
| `collectionName` | `String` | Yes | Name of your Typesense collection |
|
|
76
|
+
| `theme` | `String` | No | UI theme: 'light', 'dark', or 'system' (default) |
|
|
77
|
+
| `commonSearches` | `Array` | No | Array of suggested search terms |
|
|
78
|
+
| `searchFields` | `Object` | No | Customize field weights and highlighting |
|
|
79
|
+
|
|
80
|
+
### Search Fields Configuration
|
|
81
|
+
|
|
82
|
+
Customize search relevance with field weights and highlighting:
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
searchFields: {
|
|
86
|
+
title: { weight: 4, highlight: true },
|
|
87
|
+
excerpt: { weight: 2, highlight: true },
|
|
88
|
+
html: { weight: 1, highlight: true }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
53
93
|
|
|
54
|
-
|
|
94
|
+
The search interface can be triggered in multiple ways:
|
|
95
|
+
- Click the search icon in your Ghost theme
|
|
96
|
+
- Press `/` on your keyboard
|
|
97
|
+
- Navigate to `/#/search` URL
|
|
98
|
+
- Programmatically via `window.magicPagesSearch.openModal()`
|
|
99
|
+
|
|
100
|
+
### Keyboard Shortcuts
|
|
55
101
|
|
|
56
102
|
- `/`: Open search
|
|
57
|
-
- `↑/↓`: Navigate results
|
|
103
|
+
- `↑/↓`: Navigate through results
|
|
58
104
|
- `Enter`: Select result
|
|
59
105
|
- `Esc`: Close search
|
|
60
106
|
|
|
61
107
|
## Customization
|
|
62
108
|
|
|
63
|
-
The UI uses CSS
|
|
64
|
-
|
|
65
|
-
```css
|
|
66
|
-
#mp-search-wrapper {
|
|
67
|
-
--modal-bg: #fff;
|
|
68
|
-
--text-primary: #333;
|
|
69
|
-
--text-secondary: #666;
|
|
70
|
-
--border-color: rgba(0, 0, 0, 0.1);
|
|
71
|
-
--hover-bg: rgba(0, 0, 0, 0.05);
|
|
72
|
-
--backdrop-color: rgba(0, 0, 0, 0.5);
|
|
73
|
-
--accent-color: var(--ghost-accent-color, #1c1c1c);
|
|
74
|
-
}
|
|
109
|
+
The search UI automatically detects and uses your Ghost site's accent color by reading the `--ghost-accent-color` CSS variable. This ensures that the search interface matches your site's branding.
|
|
75
110
|
|
|
76
|
-
|
|
77
|
-
#mp-search-wrapper.dark {
|
|
78
|
-
--modal-bg: #1c1c1c;
|
|
79
|
-
--text-primary: #fff;
|
|
80
|
-
--text-secondary: #999;
|
|
81
|
-
--border-color: rgba(255, 255, 255, 0.1);
|
|
82
|
-
--hover-bg: rgba(255, 255, 255, 0.05);
|
|
83
|
-
}
|
|
84
|
-
```
|
|
111
|
+
The UI also includes a built-in dark mode that automatically activates based on the user's system preferences. It can also be overwritten in the UI's configuration.
|
|
85
112
|
|
|
86
113
|
## License
|
|
87
114
|
|
|
88
|
-
MIT © [MagicPages](https://www.magicpages.co)
|
|
115
|
+
MIT © [MagicPages](https://www.magicpages.co)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#mp-search-wrapper{--color-base-50:255 255 255;--color-base-100:250 250 250;--color-base-200:229 231 235;--color-base-300:209 213 219;--color-base-700:55 65 81;--color-base-800:31 41 55;--color-base-900:17 24 39;--color-base-950:3 7 18;--color-surface:rgb(var(--color-base-50));--color-surface-elevated:rgb(var(--color-base-100));--color-surface-hover:color-mix(in srgb,rgb(var(--color-base-950)) 4%,transparent);--color-accent-bg:color-mix(in srgb,var(--accent-color) 8%,transparent);--color-text:rgb(var(--color-base-900));--color-text-secondary:rgb(var(--color-base-700));--color-border:color-mix(in srgb,rgb(var(--color-base-950)) 8%,transparent);--color-backdrop:color-mix(in srgb,rgb(var(--color-base-950)) 60%,transparent);--accent-color:var(--ghost-accent-color,#4338ca);--accent-color-hover:color-mix(in srgb,var(--accent-color) 92%,#000);--transition-base:100ms ease;--transition-smooth:150ms ease;--shadow-sm:0 1px 2px 0 rgba(0,0,0,.05);--shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--shadow-lg:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);all:initial;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;inset:0;pointer-events:none;position:fixed;z-index:9999}.ais-SearchBox-input[type=search]::-webkit-search-cancel-button{display:none}#mp-search-wrapper.dark{--color-surface:rgb(var(--color-base-900));--color-surface-elevated:rgb(var(--color-base-800));--color-surface-hover:color-mix(in srgb,rgb(var(--color-base-50)) 4%,transparent);--color-text:rgb(var(--color-base-50));--color-text-secondary:rgb(var(--color-base-300));--color-border:color-mix(in srgb,rgb(var(--color-base-50)) 12%,transparent);--color-backdrop:color-mix(in srgb,rgb(var(--color-base-950)) 80%,transparent)}#mp-search-modal{height:100%;pointer-events:auto;position:relative;width:100%}#mp-search-modal.hidden{display:none}.mp-backdrop{backdrop-filter:blur(8px);background:var(--color-backdrop);inset:0;position:fixed;transition:opacity var(--transition-base)}.mp-modal-container{align-items:flex-start;display:flex;justify-content:center;min-height:100%;padding:1rem;position:relative;width:100%}.mp-modal-content{background:var(--color-surface);border:1px solid var(--color-border);border-radius:.75rem;box-shadow:var(--shadow-lg);margin-top:10vh;max-width:42rem;overflow:hidden;position:relative;width:100%}.mp-search-header{align-items:center;background:var(--color-surface-elevated);border-bottom:1px solid var(--color-border);display:grid;gap:1rem;grid-template-columns:1fr auto;padding:.875rem 1.5rem;position:relative}.mp-search-input-wrapper{align-items:center;position:relative;width:100%}.mp-search-input{-webkit-appearance:none;background:transparent;border:none;border-radius:.75rem;box-shadow:none;color:var(--color-text);font-size:1.125rem;height:2.5rem;outline:none;padding:.5rem .5rem .5rem 2.5rem;transition:all var(--transition-base);width:100%}.mp-search-input:focus,.mp-search-input:focus-visible{box-shadow:none;outline:none}.mp-search-input::placeholder{color:var(--color-text-secondary);opacity:.7}.mp-search-header:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='%23374151' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607'/%3E%3C/svg%3E");color:var(--color-text);content:"";height:1.25rem;left:1.5rem;opacity:.7;position:absolute;top:50%;transform:translateY(-50%);transition:opacity var(--transition-base);width:1.25rem}.dark .mp-search-header:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='%23D1D5DB' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607'/%3E%3C/svg%3E")}.mp-results-container{max-height:70vh;overflow-y:scroll;padding:.75rem calc(1.5rem - 6px) .75rem 1.5rem;scroll-behavior:smooth}.mp-modal-content:not(:has(.mp-common-searches)) .mp-results-container{padding-bottom:0}.mp-results-container::-webkit-scrollbar{width:6px}.mp-results-container::-webkit-scrollbar-track{background:transparent}.mp-results-container::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:3px}.mp-results-container>:last-child{margin-bottom:.75rem}.mp-common-searches{margin:0;padding:.75rem 6px .75rem 0}.mp-common-searches.hidden{display:none}.mp-common-searches-title{color:var(--color-text-secondary);font-size:.75rem;font-weight:600;letter-spacing:.05em;margin:0 1.5rem .75rem;text-transform:uppercase}.mp-common-search-btn{align-items:center;background:transparent;border:1px solid transparent;border-radius:.5rem;color:var(--color-text);cursor:pointer;display:flex;font-size:.875rem;padding:1rem calc(1.5rem - 6px) 1rem 1.5rem;text-align:left;text-decoration:none;transition:all var(--transition-base);width:100%}.mp-common-search-btn.mp-selected,.mp-common-search-btn:hover{background:var(--color-accent-bg)}.mp-result-link{color:inherit}.mp-result-item,.mp-result-link{cursor:pointer;display:block;text-decoration:none}.mp-result-item{border:1px solid transparent;border-radius:.75rem;margin:.5rem 0;padding:1rem 1.25rem;transition:background-color var(--transition-base);word-break:break-word}.mp-result-link.mp-selected .mp-result-item,.mp-result-link:focus .mp-result-item,.mp-result-link:hover .mp-result-item{background:var(--color-accent-bg);border-color:var(--color-border)}.mp-result-title{color:var(--color-text);font-size:1.125rem;font-weight:600;line-height:1.4;margin-bottom:.25rem;transition:color var(--transition-base);word-break:break-word}.mp-result-link.mp-selected .mp-result-title,.mp-result-link:focus .mp-result-title,.mp-result-link:hover .mp-result-title{color:var(--accent-color)}.mp-result-excerpt{color:var(--color-text-secondary);font-size:.875rem;line-height:1.6;margin-top:.25rem;word-break:break-word}.mp-keyboard-hints{display:flex;gap:.75rem;padding-left:.5rem;user-select:none;white-space:nowrap}.mp-kbd,.mp-keyboard-hints{color:var(--color-text-secondary);font-size:.75rem}.mp-kbd{background:var(--color-surface);border:1px solid var(--color-border);border-radius:.375rem;box-shadow:var(--shadow-sm);font-weight:500;padding:.125rem .375rem}.dark .mp-kbd,.dark .mp-keyboard-hints{color:rgb(var(--color-base-200))}.mp-empty-message{color:var(--color-text-secondary);font-size:1rem;padding:3rem 1.5rem;text-align:center}.mp-close-button{align-items:center;background:var(--color-surface-elevated);border:1px solid var(--color-border);border-radius:9999px;color:var(--color-text-secondary);cursor:pointer;display:flex;font-size:1.25rem;height:2rem;justify-content:center;line-height:1;padding:0;position:absolute;right:1.25rem;top:.875rem;transition:all var(--transition-base);width:2rem;z-index:50}.mp-close-button:hover{background:var(--color-surface-hover);border-color:var(--accent-color);color:var(--color-text)}.mp-close-button:focus-visible{border-color:var(--accent-color);box-shadow:0 0 0 2px var(--color-surface),0 0 0 4px var(--accent-color);outline:none}.ais-Highlight-highlighted,.ais-Snippet-highlighted{background:none;color:var(--accent-color);font-weight:600}@media (max-width:640px){.mp-keyboard-hints{display:none}.mp-search-input-wrapper{margin-right:0}.mp-modal-content{border-radius:0;height:100vh;margin-top:0}.mp-modal-container{padding:0}.mp-close-button{right:1rem;top:1rem}.mp-results-container{max-height:calc(100vh - 4.5rem);padding-bottom:1.5rem}}
|