Skip to content

Commit a0450ec

Browse files
thisisjofrankphilhawksworthjosh-collinsworthmicheleriva
authored
[WIP] Orama search (#2426)
Co-authored-by: Phil Hawksworth <[email protected]> Co-authored-by: Josh Collinsworth <[email protected]> Co-authored-by: Michele Riva <[email protected]>
1 parent ed8e68f commit a0450ec

22 files changed

+3586
-201
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
name: Deploy Orama Search Index
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
# Only trigger when documentation content changes
8+
- "runtime/**/*.md"
9+
- "deploy/**/*.md"
10+
- "examples/**/*.md"
11+
- "subhosting/**/*.md"
12+
- "lint/**/*.md"
13+
- "reference_gen/**"
14+
# Or when the build configuration changes
15+
- "deno.json"
16+
- "orama/**"
17+
18+
# Allow manual triggering for testing
19+
workflow_dispatch:
20+
inputs:
21+
force_deploy:
22+
description: "Force deploy even without content changes"
23+
required: false
24+
default: false
25+
type: boolean
26+
27+
jobs:
28+
deploy-search-index:
29+
name: Generate and Deploy Search Index
30+
runs-on: ubuntu-latest
31+
32+
steps:
33+
- name: Checkout repository
34+
uses: actions/checkout@v4
35+
with:
36+
# Fetch more history for content change detection
37+
fetch-depth: 2
38+
39+
- name: Setup Deno
40+
uses: denoland/setup-deno@v1
41+
with:
42+
deno-version: v1.x
43+
44+
- name: Check for content changes
45+
id: changes
46+
run: |
47+
if [ "${{ github.event.inputs.force_deploy }}" = "true" ]; then
48+
echo "Force deploy requested"
49+
echo "content_changed=true" >> $GITHUB_OUTPUT
50+
else
51+
# Check if any content files changed in the last commit
52+
CHANGED=$(git diff --name-only HEAD~1 HEAD | grep -E '\.(md|json)$|^reference_gen/|^orama/' || echo "")
53+
if [ -n "$CHANGED" ]; then
54+
echo "content_changed=true" >> $GITHUB_OUTPUT
55+
echo "Content files changed:"
56+
echo "$CHANGED" | sed 's/^/ /'
57+
else
58+
echo "content_changed=false" >> $GITHUB_OUTPUT
59+
echo " No content changes detected - skipping search index update"
60+
fi
61+
fi
62+
63+
- name: Generate comprehensive search index
64+
if: steps.changes.outputs.content_changed == 'true'
65+
run: |
66+
echo "Generating comprehensive Orama search index..."
67+
deno task generate:orama:full
68+
69+
- name: Upload and deploy to Orama Cloud
70+
if: steps.changes.outputs.content_changed == 'true'
71+
run: |
72+
echo "Uploading search index to Orama Cloud..."
73+
deno task upload:orama static/orama-index-full.json --deploy
74+
env:
75+
ORAMA_INDEX_ID: ${{ secrets.ORAMA_INDEX_ID }}
76+
ORAMA_PRIVATE_API_KEY: ${{ secrets.ORAMA_PRIVATE_API_KEY }}
77+
78+
- name: Report deployment success
79+
if: steps.changes.outputs.content_changed == 'true'
80+
run: |
81+
echo "Search index deployment completed successfully!"
82+
echo "Updated search includes:"
83+
echo " Documentation pages"
84+
echo " API references (Deno, Web, Node.js)"
85+
echo " Total searchable documents: ~5,856"
86+
87+
- name: Skip deployment message
88+
if: steps.changes.outputs.content_changed == 'false'
89+
run: |
90+
echo "No content changes detected - search index deployment skipped"
91+
echo "To force a deployment, use the 'workflow_dispatch' trigger with force_deploy=true"

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,9 @@ reference_gen/types
1414
static/llms.txt
1515
static/llms-full.txt
1616

17+
# Orama search index files (generated at build time)
18+
static/orama-index.json
19+
static/orama-index-*.json
20+
1721
.DS_Store
1822
.env

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,69 @@ this command:
230230
git shortlog -s -n
231231
```
232232

233+
## Orama Search Configuration
234+
235+
1. **Sign up for Orama Cloud**: Go to
236+
[https://cloud.oramasearch.com/](https://cloud.oramasearch.com/) and create
237+
an account.
238+
239+
2. **Create a new index**:
240+
- In the Orama dashboard, create a new index
241+
- Set the data source to docs.deno.com or upload the documentation content
242+
directly
243+
244+
3. **Get your credentials**:
245+
- In your Orama dashboard, you'll find your **Endpoint URL** and **Public API
246+
Key**
247+
- These are safe to include in frontend applications
248+
249+
4. **Configure the search**:
250+
- Open `search.client.ts`
251+
- Replace `YOUR_ORAMA_ENDPOINT` with your actual endpoint URL
252+
- Replace `YOUR_ORAMA_API_KEY` with your actual public API key
253+
254+
### Data Sources
255+
256+
For the Deno docs, we have several options:
257+
258+
#### Option 1: Web Crawler (Recommended)
259+
260+
- Use Orama's built-in web crawler to index your documentation site
261+
- Go to Data Sources → Web Crawler in your Orama dashboard
262+
- Add your site URL (e.g., `https://docs.deno.com`)
263+
- Configure crawling rules if needed
264+
265+
#### Option 2: Static Files
266+
267+
- Export your documentation content as JSON
268+
- Upload it directly to Orama
269+
- This gives you more control over what gets indexed
270+
271+
#### Option 3: API Integration
272+
273+
- Use Orama's REST API to programmatically add/update content
274+
- Useful to integrate with our build process
275+
276+
### Configuration Example
277+
278+
In `search.client.ts`, update the ORAMA_CONFIG object:
279+
280+
```typescript
281+
const ORAMA_CONFIG = {
282+
endpoint: "https://cloud.orama.com/v1/indexes/your-index-id",
283+
apiKey: "your-public-api-key-here",
284+
};
285+
```
286+
287+
### Customization
288+
289+
We can customize the search experience by modifying:
290+
291+
- **Search modes**: Change between "fulltext", "vector", or "hybrid" search
292+
- **Result limit**: Adjust how many results to show
293+
- **UI styling**: Modify the CSS classes in the search components
294+
- **Result formatting**: Change how search results are displayed
295+
233296
## Deployment
234297

235298
The `docs.deno.com` site is updated with every push to the `main` branch, which

_components/Header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export default function (
5757
</a>
5858
))}
5959
</nav>
60-
<div className="flex items-center gap-x-2 sm:gap-x-4 ml-auto">
60+
<div className="flex items-center gap-x-2 sm:gap-x-4 ml-auto w-full max-w-80">
6161
<data.comp.SearchInput />
6262
<data.comp.ThemeToggle />
6363
<data.comp.Hamburger />

_components/SearchInput.tsx

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,76 @@
11
export default function SearchInput() {
22
return (
3-
<>
4-
<form
5-
action="https://www.google.com/search"
6-
method="get"
7-
className="mb-0"
8-
target="_blank"
9-
>
3+
<div className="md:relative w-full">
4+
{/* ☝️ That md:relative class is crucial for making the search bar pop up in the right place. Don't change it, or add any other positioning classes, unless you're ready to account for positioning across all breakpoints. */}
5+
<div className="relative">
106
<input
117
type="search"
12-
name="q"
13-
id="search-str"
148
placeholder="Search"
15-
className="w-full min-w-24 rounded-lg text-sm leading-normal pt-1 pr-3 pb-1 pl-8 border transition-all duration-150
16-
text-foreground-primary border-foreground-tertiary hover:bg-background-secondary focus:bg-background-secondary"
17-
style="background: url(/img/search.svg) no-repeat 0.5em 50%; background-size: 1em; background-color: var(--color-foreground-quaternary);"
9+
id="orama-search-input"
10+
className="w-full min-w-24 rounded-lg placeholder:text-sm text-base leading-normal p-1 pl-8 border transition-all duration-150
11+
text-foreground-primary border-foreground-secondary hover:bg-background-secondary focus:bg-background-secondary focus:outline-offset-1"
12+
style="background: url(/img/search.svg) no-repeat 0.5em 50%; background-size: 1.25em; background-color: var(--color-background-raw);"
1813
/>
19-
<input type="hidden" name="q" id="q" value="site:deno.com" />
20-
</form>
21-
</>
14+
<kbd
15+
id="search-key"
16+
className="hidden xs:flex pointer-events-none absolute font-sans rounded-sm top-1 right-1 bottom-1 w-auto border-1 border-foreground-tertiary border-b-2 border-r-2 bg-background-primary text-foreground-secondary text-center text-xs font-bold p-2 items-center justify-center dark:bg-background-secondary dark:border-gray-700"
17+
>
18+
⌘K
19+
</kbd>
20+
<div
21+
id="orama-search-loading"
22+
className="absolute left-2 top-1/2 transform -translate-y-1/2 hidden bg-background-raw"
23+
>
24+
<div className="animate-spin rounded-full h-4 w-4 border-2 border-transparent border-r-foreground-primary bg-background-raw" />
25+
</div>
26+
<div
27+
className="sr-only"
28+
aria-live="polite"
29+
id="orama-results-announcer"
30+
>
31+
{/* Text updated by JavaScript. */}
32+
</div>
33+
</div>
34+
35+
{/* Enhanced Popover for Search Results */}
36+
<div
37+
id="orama-search-results"
38+
className="absolute inset-2 left-2 right-2 h-[calc(100vh-8rem)] top-10 md:top-full md:left-auto md:right-0 mt-2 bg-background-raw border border-foreground-tertiary rounded-xl shadow-2xl z-50 md:max-h-128 overflow-hidden hidden md:min-w-160 max-w-2xl"
39+
>
40+
<div
41+
id="orama-search-results-content"
42+
className="overflow-y-auto h-full"
43+
>
44+
{/* Results will be populated via JavaScript */}
45+
</div>
46+
47+
{/* Footer with search tips */}
48+
<div className="border-t border-foreground-tertiary bg-background-secondary px-4 py-2 sticky bottom-0">
49+
<div className="flex items-center gap-6 text-xs text-foreground-secondary">
50+
<span>
51+
<kbd className="px-1.5 py-0.5 text-xs font-semibold text-foreground-secondary bg-background-primary border-r-2 border-b-2 border border-foreground-tertiary rounded mr-1">
52+
<span aria-hidden="true">↑↓</span>
53+
<span className="sr-only">Up or down to</span>
54+
</kbd>
55+
navigate
56+
</span>
57+
<span>
58+
<kbd className="px-1.5 py-0.5 text-xs font-semibold text-foreground-secondary bg-background-primary border-r-2 border-b-2 border border-foreground-tertiary rounded mr-1">
59+
<span aria-hidden="true"></span>
60+
<span className="sr-only">Enter to</span>
61+
</kbd>
62+
select
63+
</span>
64+
<span>
65+
<kbd className="px-1.5 py-0.5 text-xs font-semibold text-foreground-secondary bg-background-primary border-r-2 border-b-2 border border-foreground-tertiary rounded mr-1">
66+
<span aria-hidden="true">ESC</span>
67+
<span className="sr-only">Escape to</span>
68+
</kbd>
69+
close
70+
</span>
71+
</div>
72+
</div>
73+
</div>
74+
</div>
2275
);
2376
}

_includes/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export default function Layout(data: Lume.Data) {
6161
<script type="module" defer src="/copy.client.js"></script>
6262
<script type="module" defer src="/tabs.client.js"></script>
6363
<script type="module" defer src="/feedback.client.js"></script>
64+
<script type="module" defer src="/search.client.js"></script>
6465
<script
6566
async
6667
src="https://www.googletagmanager.com/gtm.js?id=GTM-5B5TH8ZJ"

deno.json

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,26 @@
1515
"googleapis": "npm:googleapis@^144.0.0",
1616
"postcss": "npm:postcss@^8.5.6",
1717
"prismjs": "npm:[email protected]",
18-
"tailwindcss": "npm:tailwindcss@^4.1.11"
18+
"tailwindcss": "npm:tailwindcss@^4.1.11",
19+
"@orama/core": "jsr:@orama/core@^1.2.4"
1920
},
2021
"tasks": {
21-
"serve": "deno run --env-file -A lume.ts -s",
22-
"serve:no_logs": "LUME_LOGS=WARN deno run --env-file -A lume.ts -s",
23-
"start": "deno task serve",
24-
"dev": "deno task serve:no_logs",
25-
"build": {
26-
"description": "Full production build by default",
27-
"command": "deno task build:prod && deno task tw"
28-
},
29-
"build:prod": {
30-
"description": "Build the entire site including expensive operations",
31-
"command": "BUILD_TYPE=FULL deno run --env-file -A lume.ts"
32-
},
33-
"tw": "tailwindcss -i styles.css -o _site/styles.css --minify",
34-
"build:light": {
35-
"description": "Build the site without expensive operations",
36-
"command": "deno run --env-file -A lume.ts"
37-
},
38-
"debug": "deno task build && deno task prod",
22+
"dev": "LUME_LOGS=WARN deno run --env-file -A lume.ts -s",
23+
"serve": "deno task dev",
24+
"serve:style": "BUILD_TYPE=FULL deno task lume -s --config=_config-styleguide.ts",
25+
"start": "deno task dev",
26+
"build": "BUILD_TYPE=FULL deno run --env-file -A lume.ts && tailwindcss -i styles.css -o _site/styles.css --minify",
27+
"build:light": "deno run --env-file -A lume.ts",
3928
"prod": "cd _site && deno run --allow-read --allow-env --allow-net server.ts",
40-
"reference": "cd reference_gen && deno task types && deno task doc",
41-
"lume": "echo \"import 'lume/cli.ts'\" | deno run -A -",
4229
"test": "deno test -A",
43-
"update_lint_rules": "deno run -A update_lint_rules.ts",
44-
"serve:prod": {
45-
"description": "Build, serve, and watch just the APIs section of the docs",
46-
"command": "BUILD_TYPE=FULL deno task serve"
47-
},
48-
"serve:style": {
49-
"description": "Build, serve, and watch just the styles and styleguide",
50-
"command": "BUILD_TYPE=FULL deno task lume -s --config=_config-styleguide.ts"
51-
},
52-
"generate:llms": {
53-
"description": "Generate LLM-friendly documentation files (llms.txt and llms-full.txt) in the static directory",
54-
"command": "deno run -A generate_llms_files.ts"
55-
},
56-
"generate:llms:site": {
57-
"description": "Generate LLM-friendly documentation files directly in the _site directory",
58-
"command": "deno run -A generate_llms_files.ts _site"
59-
}
30+
"lint:update": "deno run -A update_lint_rules.ts",
31+
"generate:search": "deno run -A orama/generate_orama_index_full.ts",
32+
"generate:search:docs-only": "deno run -A orama/generate.ts",
33+
"generate:llms": "deno run -A generate_llms_files.ts",
34+
"generate:llms:site": "deno run -A generate_llms_files.ts _site",
35+
"generate:reference": "cd reference_gen && deno task types && deno task doc",
36+
"search:upload": "deno run -A orama/upload_orama_index.ts --full",
37+
"search:analyze": "deno run -A orama/analyze_orama_index.ts"
6038
},
6139
"compilerOptions": {
6240
"types": [
@@ -72,7 +50,8 @@
7250
},
7351
"exclude": [
7452
"_site",
75-
"reference_gen"
53+
"reference_gen",
54+
"orama"
7655
],
7756
"nodeModulesDir": "auto"
7857
}

0 commit comments

Comments
 (0)