feat: expand smart import to support additional citation formats

Adds detection and parsing support for more input formats that
citation.js can handle, making the smart import feature more powerful.

New supported formats:
- RIS format (common export from EndNote, RefWorks, Zotero)
- PubMed Central IDs (PMCID) in addition to existing PMID support
- Wikidata IDs (e.g., Q12345 or wikidata:Q12345)
- Zenodo records (URLs and IDs like zenodo.1234567)
- Citation File Format (CFF) for software citations

Benefits:
- Users can now paste RIS exports from reference managers directly
- Support for Wikidata citations enables citing entities/concepts
- Zenodo support facilitates citing datasets and research outputs
- CFF support enables proper software citation
- Enhanced format detection provides better user feedback

The smart parser now detects all these formats automatically and
displays the appropriate format hint to users. All formats are
processed through citation.js's robust parsing engine.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jan-Henrik Bruhn 2025-10-17 14:51:06 +02:00
parent 36f44d61ac
commit 14ccb2da5b
2 changed files with 26 additions and 4 deletions

View file

@ -175,14 +175,14 @@ const QuickAddReferenceForm = () => {
<div className="space-y-3">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
DOI, URL, BibTeX, or PubMed ID
DOI, URL, BibTeX, RIS, or Identifier
</label>
<textarea
ref={smartInputRef}
value={smartInput}
onChange={(e) => setSmartInput(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Paste DOI (10.1234/example), URL, BibTeX entry, or PubMed ID..."
placeholder="Paste DOI, URL, BibTeX, RIS, PubMed ID, ISBN, Wikidata ID, Zenodo record, or CFF..."
rows={4}
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none font-mono"
/>

View file

@ -31,12 +31,28 @@ export const isValidCitationInput = (input: string): boolean => {
// BibTeX patterns
if (/^@\w+\{/.test(trimmed)) return true;
// PubMed ID
// RIS format (starts with TY -)
if (/^TY\s+-\s+/m.test(trimmed)) return true;
// PubMed ID (PMID)
if (/^PMID:\s*\d+/i.test(trimmed)) return true;
// PubMed Central ID (PMCID)
if (/^PMC\d+/i.test(trimmed)) return true;
// ISBN
if (/^ISBN[:\s]*[\d-]+/i.test(trimmed)) return true;
// Wikidata ID (Q followed by numbers)
if (/^(wikidata:)?Q\d+$/i.test(trimmed)) return true;
// Zenodo ID or URL
if (/^zenodo\.\d+$/i.test(trimmed)) return true;
if (/zenodo\.org\/record\/\d+/i.test(trimmed)) return true;
// CFF (Citation File Format) - YAML-based
if (/^cff-version:/m.test(trimmed)) return true;
return false;
};
@ -47,10 +63,16 @@ export const getInputTypeHint = (input: string): string => {
const trimmed = input.trim();
if (/^10\.\d{4,}\//.test(trimmed)) return 'DOI';
if (/zenodo\.org\/record\/\d+/i.test(trimmed)) return 'Zenodo URL';
if (/^zenodo\.\d+$/i.test(trimmed)) return 'Zenodo ID';
if (/^https?:\/\//.test(trimmed)) return 'URL';
if (/^@\w+\{/.test(trimmed)) return 'BibTeX';
if (/^PMID:/i.test(trimmed)) return 'PubMed ID';
if (/^TY\s+-\s+/m.test(trimmed)) return 'RIS Format';
if (/^PMID:/i.test(trimmed)) return 'PubMed ID (PMID)';
if (/^PMC\d+/i.test(trimmed)) return 'PubMed Central ID (PMCID)';
if (/^ISBN/i.test(trimmed)) return 'ISBN';
if (/^(wikidata:)?Q\d+$/i.test(trimmed)) return 'Wikidata ID';
if (/^cff-version:/m.test(trimmed)) return 'Citation File Format (CFF)';
return 'Unknown';
};