hal-search 0.1.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/LICENSE +21 -0
- package/README.md +214 -0
- package/dist/HalSearch.d.ts +23 -0
- package/dist/api.d.ts +12 -0
- package/dist/embed.d.ts +21 -0
- package/dist/hal-search.es.js +482 -0
- package/dist/hal-search.es.js.map +1 -0
- package/dist/hal-search.umd.js +254 -0
- package/dist/hal-search.umd.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/levels.d.ts +6 -0
- package/dist/renderer.d.ts +5 -0
- package/dist/styles.d.ts +3 -0
- package/dist/svg-renderer.d.ts +11 -0
- package/dist/types.d.ts +75 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jey Puget Gil
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# hal-search
|
|
2
|
+
|
|
3
|
+
A zero-dependency TypeScript library for querying and displaying articles from the [HAL Open Archive](https://hal.science/) API.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Goal
|
|
8
|
+
|
|
9
|
+
**hal-search** lets you embed a live, paginated list of academic publications from the HAL API into any web page with a single class instantiation. It handles:
|
|
10
|
+
|
|
11
|
+
- Building the correct HAL API query from a user ID or free-text query
|
|
12
|
+
- Fetching results at a configurable level of detail (minimal → full)
|
|
13
|
+
- Rendering styled article cards with pagination
|
|
14
|
+
- Exposing callbacks for results and errors
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# from npm (once published)
|
|
22
|
+
npm install hal-search
|
|
23
|
+
|
|
24
|
+
# or use the built files directly
|
|
25
|
+
dist/hal-search.es.js # ES module
|
|
26
|
+
dist/hal-search.umd.js # UMD (browser global: window.HalSearch)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Basic example
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<div id="publications"></div>
|
|
37
|
+
|
|
38
|
+
<script type="module">
|
|
39
|
+
import { HalSearch } from './dist/hal-search.es.js';
|
|
40
|
+
|
|
41
|
+
const hs = new HalSearch({
|
|
42
|
+
container: '#publications',
|
|
43
|
+
lvl: 1,
|
|
44
|
+
rows: 10,
|
|
45
|
+
onResults: (res) => console.log(`${res.response.numFound} results`),
|
|
46
|
+
onError: (err) => console.error(err.message),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
hs.search({ uid: 'authIdHal_s:jdupont' });
|
|
50
|
+
</script>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Constructor options
|
|
54
|
+
|
|
55
|
+
| Option | Type | Default | Description |
|
|
56
|
+
|----------------|-----------------------------------|---------|-------------|
|
|
57
|
+
| `container` | `HTMLElement \| string` | — | Target DOM element or CSS selector (optional if output='svg') |
|
|
58
|
+
| `lvl` | `0 \| 1 \| 2 \| 3` | `1` | Level of detail (see below) |
|
|
59
|
+
| `rows` | `number` | `10` | Results per page |
|
|
60
|
+
| `apiBase` | `string` | HAL URL | Override the API base URL |
|
|
61
|
+
| `injectStyles` | `boolean` | `true` | Auto-inject the default stylesheet |
|
|
62
|
+
| `onResults` | `(res: HalApiResponse) => void` | — | Called on every successful fetch |
|
|
63
|
+
| `onError` | `(err: Error) => void` | — | Called when the fetch fails |
|
|
64
|
+
|
|
65
|
+
### Methods
|
|
66
|
+
|
|
67
|
+
| Method | Description |
|
|
68
|
+
|--------|-------------|
|
|
69
|
+
| `search({ uid, rows?, start? })` | Start a new search. Returns `Promise<SVGSVGElement>` if headless SVG mode. |
|
|
70
|
+
| `setLevel(lvl)` | Change detail level and re-fetch. Returns `Promise<SVGSVGElement>` if headless SVG mode. |
|
|
71
|
+
| `goToPage(n)` | Jump to page `n` (1-based). Returns `Promise<SVGSVGElement>` if headless SVG mode. |
|
|
72
|
+
| `nextPage()` | Go to the next page. Returns `Promise<SVGSVGElement>` if headless SVG mode. |
|
|
73
|
+
| `prevPage()` | Go to the previous page. Returns `Promise<SVGSVGElement>` if headless SVG mode. |
|
|
74
|
+
| `destroy()` | Clear the container (if one was provided) |
|
|
75
|
+
|
|
76
|
+
### Headless SVG generation
|
|
77
|
+
|
|
78
|
+
You can generate a standalone SVG without attaching it to the DOM by omitting the `container` option and setting `output: 'svg'`. The `search()` method (and pagination methods) will resolve with the SVG element.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
const hs = new HalSearch({
|
|
82
|
+
output: 'svg',
|
|
83
|
+
lvl: 2,
|
|
84
|
+
rows: 5,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const svgElement = await hs.search({ uid: 'authIdHal_s:jdupont' });
|
|
88
|
+
document.body.appendChild(svgElement);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Detail levels
|
|
92
|
+
|
|
93
|
+
The `lvl` parameter controls which HAL fields are requested and how much information is shown per article.
|
|
94
|
+
|
|
95
|
+
| Level | Name | Fields fetched | What is displayed |
|
|
96
|
+
|-------|------|---------------|-------------------|
|
|
97
|
+
| `0` | Minimal | `docid`, `label_s`, `uri_s` | Citation label + link |
|
|
98
|
+
| `1` | Basic *(default)* | + `title_s`, `authFullName_s`, `publicationDate_s`, `docType_s` | Title, authors, year, document type |
|
|
99
|
+
| `2` | Detailed | + `keyword_s`, `domain_s`, `openAccess_bool`, `language_s`, `conferenceTitle_s` | All of the above + tags, OA badge, conference |
|
|
100
|
+
| `3` | Full | `*` (all fields) | Adds the abstract of the paper |
|
|
101
|
+
|
|
102
|
+
### Theming
|
|
103
|
+
|
|
104
|
+
Default styles use CSS custom properties. Override any of them on the container or globally:
|
|
105
|
+
|
|
106
|
+
```css
|
|
107
|
+
#publications {
|
|
108
|
+
--hal-accent: #e63946;
|
|
109
|
+
--hal-bg-article: #fff8f0;
|
|
110
|
+
--hal-radius: 4px;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
| Variable | Default |
|
|
115
|
+
|----------|---------|
|
|
116
|
+
| `--hal-accent` | `#0052cc` |
|
|
117
|
+
| `--hal-accent-hover` | `#003d99` |
|
|
118
|
+
| `--hal-bg` | `#ffffff` |
|
|
119
|
+
| `--hal-bg-article` | `#fafafa` |
|
|
120
|
+
| `--hal-border` | `#e0e0e0` |
|
|
121
|
+
| `--hal-text` | `#1a1a1a` |
|
|
122
|
+
| `--hal-text-muted` | `#666666` |
|
|
123
|
+
| `--hal-radius` | `6px` |
|
|
124
|
+
|
|
125
|
+
Disable auto-injection with `injectStyles: false` and provide your own stylesheet.
|
|
126
|
+
|
|
127
|
+
### Building a query
|
|
128
|
+
|
|
129
|
+
The `uid` field passed to `search()` maps directly to the `q` parameter of the HAL Solr API, so any valid Solr query works:
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
// Free-text
|
|
133
|
+
hs.search({ uid: 'machine learning' });
|
|
134
|
+
|
|
135
|
+
// Author by HAL identifier
|
|
136
|
+
hs.search({ uid: 'authIdHal_s:jdupont' });
|
|
137
|
+
|
|
138
|
+
// By lab structure
|
|
139
|
+
hs.search({ uid: 'structId_i:123456' });
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
See the [HAL API documentation](https://api.archives-ouvertes.fr/docs/search) for the full query syntax.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Running the example
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm run example
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
This builds the library and serves the interactive demo at **http://localhost:8080/example/**. The demo lets you switch queries, levels, and page size in real time.
|
|
153
|
+
|
|
154
|
+
To run the development sandbox (requires Vite):
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm run dev
|
|
158
|
+
# open http://localhost:5173
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Contributing
|
|
164
|
+
|
|
165
|
+
### Project structure
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
src/
|
|
169
|
+
index.ts # Public exports
|
|
170
|
+
HalSearch.ts # Main class
|
|
171
|
+
api.ts # URL builder + fetch logic
|
|
172
|
+
levels.ts # Field lists per detail level
|
|
173
|
+
renderer.ts # DOM rendering
|
|
174
|
+
styles.ts # Default CSS
|
|
175
|
+
types.ts # TypeScript interfaces
|
|
176
|
+
example/
|
|
177
|
+
index.html # Interactive demo
|
|
178
|
+
dist/ # Built output (generated)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Development setup
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone <repo>
|
|
185
|
+
cd hal-search
|
|
186
|
+
npm install
|
|
187
|
+
npm run dev # live dev server at localhost:5173
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Building
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm run build
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Produces:
|
|
197
|
+
|
|
198
|
+
| File | Format | Use case |
|
|
199
|
+
|------|--------|----------|
|
|
200
|
+
| `dist/hal-search.es.js` | ES module | Bundlers, `<script type="module">` |
|
|
201
|
+
| `dist/hal-search.umd.js` | UMD | `<script>` tag, CommonJS |
|
|
202
|
+
| `dist/index.d.ts` | TypeScript types | TypeScript consumers |
|
|
203
|
+
|
|
204
|
+
### Guidelines
|
|
205
|
+
|
|
206
|
+
- **TypeScript strict mode** is enabled — all code must type-check cleanly.
|
|
207
|
+
- Keep the library **zero-dependency** at runtime; dev dependencies are fine.
|
|
208
|
+
- Rendering lives in `renderer.ts`, API logic in `api.ts` — keep concerns separated.
|
|
209
|
+
- Test new features against both the dev sandbox (`index.html`) and the example page (`example/index.html`).
|
|
210
|
+
- Follow the existing naming conventions for CSS classes (`.hal-*`).
|
|
211
|
+
|
|
212
|
+
### Useful link
|
|
213
|
+
|
|
214
|
+
- [HAL API documentation](https://api.archives-ouvertes.fr/docs/search)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HalSearchOptions, SearchParams, DetailLevel } from './types';
|
|
2
|
+
export declare class HalSearch {
|
|
3
|
+
private readonly container?;
|
|
4
|
+
private options;
|
|
5
|
+
private pagination;
|
|
6
|
+
private currentUid;
|
|
7
|
+
constructor(options: HalSearchOptions);
|
|
8
|
+
/** Start a new search, resetting to page 1. */
|
|
9
|
+
search(params: SearchParams): Promise<SVGSVGElement | void>;
|
|
10
|
+
/** Navigate to a specific page number (1-based). */
|
|
11
|
+
goToPage(page: number): Promise<SVGSVGElement | void>;
|
|
12
|
+
/** Navigate to the next page. */
|
|
13
|
+
nextPage(): Promise<SVGSVGElement | void>;
|
|
14
|
+
/** Navigate to the previous page. */
|
|
15
|
+
prevPage(): Promise<SVGSVGElement | void>;
|
|
16
|
+
/** Change the detail level and re-fetch the current results. */
|
|
17
|
+
setLevel(lvl: DetailLevel): Promise<SVGSVGElement | void>;
|
|
18
|
+
/** Clear the container and remove rendered content. */
|
|
19
|
+
destroy(): void;
|
|
20
|
+
private _fetch;
|
|
21
|
+
private _resolveContainer;
|
|
22
|
+
private _updatePagination;
|
|
23
|
+
}
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HalApiResponse, DetailLevel } from './types';
|
|
2
|
+
export declare const DEFAULT_BASE = "https://api.archives-ouvertes.fr/search/";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a HAL API search URL from the given parameters.
|
|
5
|
+
* Uses URLSearchParams to safely encode special characters in uid.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildUrl(uid: string, lvl: DetailLevel, rows: number, start: number, base?: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Fetches articles from the HAL API.
|
|
10
|
+
* Throws on HTTP errors or non-zero API status codes.
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchArticles(uid: string, lvl: DetailLevel, rows: number, start: number, base?: string): Promise<HalApiResponse>;
|
package/dist/embed.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DetailLevel } from './types';
|
|
2
|
+
export interface EmbedOptions {
|
|
3
|
+
/** Base URL where embed.html is hosted */
|
|
4
|
+
embedBase: string;
|
|
5
|
+
/** Search query or author UID */
|
|
6
|
+
uid: string;
|
|
7
|
+
/** Detail level 0-3 */
|
|
8
|
+
lvl?: DetailLevel;
|
|
9
|
+
/** Results per page */
|
|
10
|
+
rows?: number;
|
|
11
|
+
/** Render mode: 'html' (default) for interactive cards, 'svg' for a static SVG */
|
|
12
|
+
type?: 'html' | 'svg';
|
|
13
|
+
/** iframe width (CSS value) */
|
|
14
|
+
width?: string;
|
|
15
|
+
/** iframe height (CSS value) */
|
|
16
|
+
height?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Builds the URL for the embeddable page with query parameters. */
|
|
19
|
+
export declare function buildEmbedUrl(options: EmbedOptions): string;
|
|
20
|
+
/** Returns a ready-to-paste `<iframe>` HTML snippet. */
|
|
21
|
+
export declare function buildEmbedSnippet(options: EmbedOptions): string;
|