Skip to content

Commit 16980d9

Browse files
feat: enhance resource schema, update badge design with integrated logo, and standardize resource routing to use ID instead of slug
1 parent 2c8729b commit 16980d9

6 files changed

Lines changed: 85 additions & 20 deletions

File tree

‎scripts/generateOpenApi.js‎

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,16 @@ const openApiSchema = {
9393
"properties": {
9494
"name": { "type": "string" },
9595
"wikidataId": { "type": ["string", "null"] },
96-
"rorId": { "type": ["string", "null"] }
96+
"rorId": { "type": ["string", "null"] },
97+
"rorName": { "type": ["string", "null"] },
98+
"rorTypes": {
99+
"type": "array",
100+
"items": { "type": "string" }
101+
},
102+
"rorCountry": { "type": ["string", "null"] },
103+
"rorCity": { "type": ["string", "null"] },
104+
"rorEstablished": { "type": ["string", "null"] },
105+
"rorAutoMatched": { "type": "boolean" }
97106
}
98107
}
99108
},
@@ -103,15 +112,33 @@ const openApiSchema = {
103112
"type": "object",
104113
"properties": {
105114
"title": { "type": "string" },
106-
"link": { "type": "string", "format": "uri" }
115+
"link": { "type": "string", "format": "uri" },
116+
"wikidataId": { "type": ["string", "null"] }
107117
}
108118
}
109119
},
110-
"permalink": { "type": ["string", "null"] },
111-
"rorTypes": {
120+
"instructions": {
121+
"type": "array",
122+
"items": { "type": "string" }
123+
},
124+
"macroCategories": {
112125
"type": "array",
113126
"items": { "type": "string" }
114127
},
128+
"dataTypeMappings": {
129+
"type": "object",
130+
"additionalProperties": { "type": ["string", "null"] }
131+
},
132+
"countryMappings": {
133+
"type": "object",
134+
"additionalProperties": { "type": ["string", "null"] }
135+
},
136+
"compensationWikidataId": {
137+
"type": ["string", "array", "null"],
138+
"items": { "type": "string" }
139+
},
140+
"permalink": { "type": ["string", "null"] },
141+
"isCitedOnWikidata": { "type": "boolean" },
115142
"wikidataReferenceUrl": { "type": ["string", "null"], "format": "uri" }
116143
}
117144
}

‎scripts/generateResourceJSON.js‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,15 @@ try {
2020
rorData = JSON.parse(readFileSync(rorPath, 'utf8'));
2121
} catch(e) {}
2222

23+
const { dataTypeToMacroCategory } = await import('../src/data/resources.js');
24+
2325
const enrichedResources = wikidataResources.map(resource => {
24-
// Merge ROR data into organizations
26+
// 1. Compute Macro Categories (consistent with src/data/resources.js)
27+
const macroCategories = Array.from(new Set(
28+
(resource.dataTypes || []).map(type => dataTypeToMacroCategory[type]).filter(Boolean)
29+
)).sort();
30+
31+
// 2. Merge ROR data into organizations
2532
const enrichedOrgs = (resource.organizations || []).map(org => {
2633
const ror = rorData[org.name];
2734
if (ror && ror.rorId && ror.name) {
@@ -42,6 +49,7 @@ try {
4249
return {
4350
...resource,
4451
organizations: enrichedOrgs,
52+
macroCategories,
4553
permalink: `https://yourselftoscience.org/resource/${resource.id}`,
4654
isCitedOnWikidata: resource.resourceWikidataId ? citedQIDs.has(resource.resourceWikidataId) : false,
4755
wikidataReferenceUrl: (resource.resourceWikidataId && citedQIDs.has(resource.resourceWikidataId)) ? `https://www.wikidata.org/wiki/${resource.resourceWikidataId}` : null

‎src/app/api/badge/[slug]/route.js‎

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import { readFileSync } from 'fs';
2+
import { join } from 'path';
13
import ObjectData from '@/../public/resources_wikidata.json';
24

3-
export const runtime = 'edge';
5+
// We remove 'edge' runtime to allow Node.js 'fs' access during the 'next build'
6+
// static generation phase for the 'output: export' configuration.
7+
export const runtime = 'nodejs';
48

59
// Optionally statically generate standard badges
610
export async function generateStaticParams() {
7-
return ObjectData.map((resource) => ({ slug: resource.slug }));
11+
return ObjectData.map((resource) => ({ slug: resource.id }));
812
}
913

1014
export async function GET(request, { params }) {
@@ -15,6 +19,17 @@ export async function GET(request, { params }) {
1519
return new Response('Not Found', { status: 404 });
1620
}
1721

22+
// Read official logo content from public directory
23+
let logoSvgContent = '';
24+
try {
25+
const logoPath = join(process.cwd(), 'public/logo-tm.svg');
26+
logoSvgContent = readFileSync(logoPath, 'utf8');
27+
// Clean up the SVG for nesting: remove XML declaration and doctype
28+
logoSvgContent = logoSvgContent.replace(/<\?xml.*\?>/g, '').replace(/<!DOCTYPE.*?>/g, '');
29+
} catch (error) {
30+
console.error('Failed to read logo-tm.svg:', error);
31+
}
32+
1833
// Calculate prestige completeness
1934
const isComplete = resource.yearLaunched != null &&
2035
resource.isActivelyRecruiting != null &&
@@ -25,12 +40,15 @@ export async function GET(request, { params }) {
2540
const rightText = isComplete ? "Complete Data Source" : "Verified Data Source";
2641

2742
// Approximate width calculation (standard fonts)
28-
const leftWidth = 120;
43+
const logoWidth = 24;
44+
const leftTextWidth = 185; // Increased to fit "Yourself to Science™" comfortably
45+
const leftWidth = logoWidth + leftTextWidth;
2946
const rightWidth = isComplete ? 135 : 130;
3047
const totalWidth = leftWidth + rightWidth;
3148

3249
// Official Theme Colors
33-
const colorLeft = "#1A1C1E"; // m3-on-surface (black title color)
50+
const colorLeft = "#ffffff"; // Header match (white)
51+
const textColor = "#202124"; // google-text
3452
// Gold badge vs standard blue badge
3553
const colorRight = isComplete ? "#FDBB2D" : "#1156B0"; // stroke-yellow-dark / google-blue
3654

@@ -40,6 +58,10 @@ export async function GET(request, { params }) {
4058
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
4159
<stop offset="1" stop-opacity=".1"/>
4260
</linearGradient>
61+
<linearGradient id="g" x1="0%" y1="0%" x2="0%" y2="100%">
62+
<stop offset="0%" stop-color="#ffd92d"/>
63+
<stop offset="100%" stop-color="#B35F00"/>
64+
</linearGradient>
4365
<clipPath id="r">
4466
<rect width="${totalWidth}" height="20" rx="3" fill="#fff"/>
4567
</clipPath>
@@ -48,11 +70,20 @@ export async function GET(request, { params }) {
4870
<rect x="${leftWidth}" width="${rightWidth}" height="20" fill="${colorRight}"/>
4971
<rect width="${totalWidth}" height="20" fill="url(#s)"/>
5072
</g>
51-
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
52-
<text aria-hidden="true" x="${leftWidth * 5}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${(leftWidth - 20) * 10}">${leftText}</text>
53-
<text x="${leftWidth * 5}" y="140" transform="scale(.1)" fill="#fff" textLength="${(leftWidth - 20) * 10}">${leftText}</text>
54-
<text aria-hidden="true" x="${(leftWidth + rightWidth / 2) * 10}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${(rightWidth - 20) * 10}">${rightText}</text>
55-
<text x="${(leftWidth + rightWidth / 2) * 10}" y="140" transform="scale(.1)" fill="#fff" textLength="${(rightWidth - 20) * 10}">${rightText}</text>
73+
<g font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
74+
<!-- Official 'Yourself to Science' Logo Integrated via File Read -->
75+
<g transform="translate(4, 2) scale(0.069)">
76+
${logoSvgContent}
77+
</g>
78+
79+
<g transform="scale(.1)">
80+
<text x="${(logoWidth + (leftTextWidth / 2)) * 10}" y="140" fill="${textColor}" text-anchor="middle">
81+
<tspan font-weight="500">Your</tspan><tspan fill="url(#g)" stroke="#ffd92d" stroke-width="3" font-weight="bold">self</tspan><tspan font-weight="500"> to Science</tspan>
82+
<tspan font-size="70" baseline-shift="super">™</tspan>
83+
</text>
84+
</g>
85+
86+
<text x="${(leftWidth + rightWidth / 2) * 10}" y="140" transform="scale(.1)" fill="#fff" text-anchor="middle" textLength="${(rightWidth - 20) * 10}">${rightText}</text>
5687
</g>
5788
</svg>`;
5889

‎src/app/explore/page.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ export default function ExplorePage() {
492492
{col.key === 'title' ? (
493493
<div>
494494
<Link
495-
href={`/resource/${resource.slug}`}
495+
href={`/resource/${resource.id}`}
496496
className="font-medium text-slate-900 hover:text-blue-600 transition-colors group-hover:text-blue-600"
497497
>
498498
{resource.title}

‎src/app/resource/[slug]/page.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,11 @@ export default function ResourcePage({ params }) {
405405
<h4 className="text-lg font-semibold text-gray-800 mb-2">Showcase your commitment to Open Science</h4>
406406
<p className="text-sm text-gray-600 mb-4">By embedding this verified reference badge on your website, you publicly confirm your project&apos;s transparency metrics and establish your verifiable link to the global knowledge graph monitored by researchers, policy makers, and ecosystem investors.</p>
407407
<div className="bg-gray-50 border border-gray-200 p-4 rounded-md flex flex-col md:flex-row items-center justify-between gap-4">
408-
<img src={`/api/badge/${resource.slug}`} alt="Dataset Status Badge" className="h-5" />
408+
<img src={`/api/badge/${resource.id}`} alt="Dataset Status Badge" className="h-5" />
409409
<div className="text-xs font-mono text-gray-500 break-all w-full text-center md:text-left selection:bg-blue-100">
410-
{`[![Verified Source](https://yourselftoscience.org/api/badge/${resource.slug})](https://yourselftoscience.org/resource/${resource.slug})`}
410+
{`[![Verified Source](https://yourselftoscience.org/api/badge/${resource.id})](https://yourselftoscience.org/resource/${resource.id})`}
411411
</div>
412-
<CopyButton text={`[![Verified Source](https://yourselftoscience.org/api/badge/${resource.slug})](https://yourselftoscience.org/resource/${resource.slug})`} />
412+
<CopyButton text={`[![Verified Source](https://yourselftoscience.org/api/badge/${resource.id})](https://yourselftoscience.org/resource/${resource.id})`} />
413413
</div>
414414
<div className="mt-4 text-sm text-blue-600">
415415
<a href={`mailto:science@yourselftoscience.org?subject=Open%20Science%20Verification%3A%20${encodeURIComponent(resource.title)}`} className="hover:underline font-medium inline-flex items-center">

‎src/data/resources.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ export const rawResources = [
18161816
];
18171817

18181818

1819-
const dataTypeToMacroCategory = {
1819+
export const dataTypeToMacroCategory = {
18201820
// Organ, Body & Tissue Donation
18211821
'Body': 'Organ, Body & Tissue Donation',
18221822
'Organ': 'Organ, Body & Tissue Donation',
@@ -1846,7 +1846,6 @@ const dataTypeToMacroCategory = {
18461846

18471847
'Conversational AI data': 'Health & Digital Data',
18481848

1849-
18501849
// Clinical Trials
18511850
'Clinical trials': 'Clinical Trials',
18521851
};

0 commit comments

Comments
 (0)