@ca-plant-list/ca-plant-list 0.4.8 → 0.4.9
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/.github/workflows/main.yml +20 -0
- package/.vscode/settings.json +7 -2
- package/data/glossary/perianth.md +1 -0
- package/data/taxa.csv +5 -3
- package/data/text/Toxicoscordion-fremontii.md +1 -0
- package/data/text/Toxicoscordion-paniculatum.md +1 -0
- package/data/text/Toxicoscordion-venenosum-var-venenosum.md +1 -0
- package/ebook/css/main.css +9 -1
- package/eslint.config.mjs +9 -9
- package/lib/ebook/images.js +79 -52
- package/lib/ebook/pages/taxonpage.js +25 -27
- package/lib/ebook/plantbook.js +147 -139
- package/lib/htmltaxon.js +124 -117
- package/lib/inat_photo.js +15 -15
- package/lib/progressmeter.js +29 -0
- package/lib/web/pagetaxon.js +199 -190
- package/package.json +4 -3
- package/scripts/photos.js +68 -0
- package/types/classes.d.ts +14 -20
- package/data/photos.csv +0 -9
- package/lib/ebook/taxonimage.js +0 -23
package/lib/web/pagetaxon.js
CHANGED
@@ -8,197 +8,206 @@ import { Markdown } from "../markdown.js";
|
|
8
8
|
import { Config } from "../config.js";
|
9
9
|
|
10
10
|
class PageTaxon extends GenericPage {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
-
|
25
|
-
#getInfoLinks() {
|
26
|
-
const links = [];
|
27
|
-
const jepsonID = this.#taxon.getJepsonID();
|
28
|
-
if (jepsonID) {
|
29
|
-
links.push(Jepson.getEFloraLink(jepsonID));
|
11
|
+
#config;
|
12
|
+
#taxon;
|
13
|
+
|
14
|
+
/**
|
15
|
+
* @param {string} outputDir
|
16
|
+
* @param {Config} config
|
17
|
+
* @param {Taxon} taxon
|
18
|
+
*/
|
19
|
+
constructor(outputDir, config, taxon) {
|
20
|
+
super(outputDir, taxon.getName(), taxon.getBaseFileName());
|
21
|
+
this.#config = config;
|
22
|
+
this.#taxon = taxon;
|
30
23
|
}
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
this.#config.getCountyCodes().join("!") +
|
52
|
-
"&incobs=f&taxon=" +
|
53
|
-
this.#taxon.getCalfloraName().replaceAll(" ", "+"),
|
54
|
-
"Calflora",
|
55
|
-
{},
|
56
|
-
true
|
57
|
-
)
|
58
|
-
);
|
59
|
-
const iNatID = this.#taxon.getINatID();
|
60
|
-
if (iNatID) {
|
61
|
-
const projectId = links.push(
|
62
|
-
HTML.getLink(
|
63
|
-
ExternalSites.getInatObsLink({
|
64
|
-
project_id: this.#config.getConfigValue("inat", "project_id"),
|
65
|
-
subview: "map",
|
66
|
-
taxon_id: iNatID,
|
67
|
-
}),
|
68
|
-
"iNaturalist",
|
69
|
-
{},
|
70
|
-
true
|
71
|
-
)
|
72
|
-
);
|
24
|
+
|
25
|
+
#getInfoLinks() {
|
26
|
+
const links = [];
|
27
|
+
const jepsonID = this.#taxon.getJepsonID();
|
28
|
+
if (jepsonID) {
|
29
|
+
links.push(Jepson.getEFloraLink(jepsonID));
|
30
|
+
}
|
31
|
+
const cfLink = this.#taxon.getCalfloraTaxonLink();
|
32
|
+
if (cfLink) {
|
33
|
+
links.push(cfLink);
|
34
|
+
}
|
35
|
+
const iNatLink = this.#taxon.getINatTaxonLink();
|
36
|
+
if (iNatLink) {
|
37
|
+
links.push(iNatLink);
|
38
|
+
}
|
39
|
+
const rpiLink = this.#taxon.getRPITaxonLink();
|
40
|
+
if (rpiLink) {
|
41
|
+
links.push(rpiLink);
|
42
|
+
}
|
43
|
+
return links;
|
73
44
|
}
|
74
45
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
46
|
+
#getObsLinks() {
|
47
|
+
const links = [];
|
48
|
+
links.push(
|
49
|
+
HTML.getLink(
|
50
|
+
"https://www.calflora.org/entry/observ.html?track=m#srch=t&grezc=5&cols=b&lpcli=t&cc=" +
|
51
|
+
this.#config.getCountyCodes().join("!") +
|
52
|
+
"&incobs=f&taxon=" +
|
53
|
+
this.#taxon.getCalfloraName().replaceAll(" ", "+"),
|
54
|
+
"Calflora",
|
55
|
+
{},
|
56
|
+
true,
|
57
|
+
),
|
58
|
+
);
|
59
|
+
const iNatID = this.#taxon.getINatID();
|
60
|
+
if (iNatID) {
|
61
|
+
links.push(
|
62
|
+
HTML.getLink(
|
63
|
+
ExternalSites.getInatObsLink({
|
64
|
+
project_id: this.#config.getConfigValue(
|
65
|
+
"inat",
|
66
|
+
"project_id",
|
67
|
+
),
|
68
|
+
subview: "map",
|
69
|
+
taxon_id: iNatID,
|
70
|
+
}),
|
71
|
+
"iNaturalist",
|
72
|
+
{},
|
73
|
+
true,
|
74
|
+
),
|
75
|
+
);
|
76
|
+
}
|
77
|
+
|
78
|
+
return links;
|
92
79
|
}
|
93
|
-
return html;
|
94
|
-
}
|
95
80
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
81
|
+
/**
|
82
|
+
* @param {string[]} list
|
83
|
+
* @param {string} header
|
84
|
+
* @param {string} className
|
85
|
+
*/
|
86
|
+
#getListSectionHTML(list, header, className) {
|
87
|
+
let html = "";
|
88
|
+
if (list.length > 0) {
|
89
|
+
html += '<div class="section nobullet ' + className + '">';
|
90
|
+
html += HTML.textElement("h2", header);
|
91
|
+
html += "<ul>";
|
92
|
+
html += HTML.arrayToLI(list);
|
93
|
+
html += "</ul>";
|
94
|
+
html += "</div>";
|
95
|
+
}
|
96
|
+
return html;
|
100
97
|
}
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
98
|
+
|
99
|
+
#getRarityInfo() {
|
100
|
+
const cnpsRank = this.#taxon.getRPIRankAndThreat();
|
101
|
+
if (!cnpsRank) {
|
102
|
+
return "";
|
103
|
+
}
|
104
|
+
const ranks = [];
|
105
|
+
|
106
|
+
ranks.push(
|
107
|
+
HTML.textElement("span", "CNPS Rare Plant Rank:", {
|
108
|
+
class: "label",
|
109
|
+
}) +
|
110
|
+
HTML.getToolTip(
|
111
|
+
cnpsRank,
|
112
|
+
this.#taxon.getRPIRankAndThreatTooltip(),
|
113
|
+
),
|
114
|
+
);
|
115
|
+
if (this.#taxon.getCESA()) {
|
116
|
+
ranks.push(
|
117
|
+
HTML.textElement("span", "CESA:", { class: "label" }) +
|
118
|
+
RarePlants.getCESADescription(this.#taxon.getCESA()),
|
119
|
+
);
|
120
|
+
}
|
121
|
+
|
122
|
+
return HTML.wrap("div", "<ul>" + HTML.arrayToLI(ranks) + "</ul>", {
|
123
|
+
class: "section",
|
124
|
+
});
|
113
125
|
}
|
114
126
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
);
|
127
|
+
#getRelatedTaxaLinks() {
|
128
|
+
const links = [];
|
129
|
+
const genus = this.#taxon.getGenus();
|
130
|
+
if (genus) {
|
131
|
+
const taxa = genus.getTaxa();
|
132
|
+
if (taxa.length > 1) {
|
133
|
+
for (const taxon of taxa) {
|
134
|
+
links.push(
|
135
|
+
taxon.getHTMLLink(
|
136
|
+
taxon.getName() !== this.#taxon.getName(),
|
137
|
+
),
|
138
|
+
);
|
139
|
+
}
|
140
|
+
}
|
130
141
|
}
|
131
|
-
|
142
|
+
return links;
|
132
143
|
}
|
133
|
-
return links;
|
134
|
-
}
|
135
144
|
|
136
|
-
|
137
|
-
|
138
|
-
|
145
|
+
#getSynonyms() {
|
146
|
+
return this.#taxon.getSynonyms();
|
147
|
+
}
|
139
148
|
|
140
|
-
|
141
|
-
|
149
|
+
render() {
|
150
|
+
let html = this.getFrontMatter();
|
142
151
|
|
143
|
-
|
152
|
+
html += '<div class="wrapper">';
|
144
153
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
154
|
+
const cn = this.#taxon.getCommonNames();
|
155
|
+
if (cn.length > 0) {
|
156
|
+
html += HTML.textElement("div", cn.join(", "), {
|
157
|
+
class: "section common-names",
|
158
|
+
});
|
159
|
+
}
|
151
160
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
161
|
+
html += HTML.textElement(
|
162
|
+
"div",
|
163
|
+
this.#taxon.getStatusDescription(this.#config),
|
164
|
+
{ class: "section native-status" },
|
165
|
+
);
|
166
|
+
|
167
|
+
const family = this.#taxon.getFamily();
|
168
|
+
html += HTML.wrap(
|
169
|
+
"div",
|
170
|
+
HTML.textElement("span", "Family:", { class: "label" }) +
|
171
|
+
HTML.getLink("./" + family.getFileName(), family.getName()),
|
172
|
+
{ class: "section" },
|
173
|
+
);
|
174
|
+
|
175
|
+
html += this.#getRarityInfo();
|
176
|
+
|
177
|
+
html += "</div>";
|
178
|
+
|
179
|
+
html += HTMLTaxon.getFlowerInfo(this.#taxon, undefined, false);
|
180
|
+
|
181
|
+
html += this.getMarkdown();
|
182
|
+
|
183
|
+
html += '<div class="grid borders">';
|
184
|
+
html += this.#getListSectionHTML(
|
185
|
+
this.#getInfoLinks(),
|
186
|
+
"References",
|
187
|
+
"info",
|
188
|
+
);
|
189
|
+
html += this.#getListSectionHTML(
|
190
|
+
this.#getObsLinks(),
|
191
|
+
"Observations",
|
192
|
+
"obs",
|
193
|
+
);
|
194
|
+
html += this.#getListSectionHTML(
|
195
|
+
this.#getRelatedTaxaLinks(),
|
196
|
+
"Related Species",
|
197
|
+
"rel-taxa",
|
198
|
+
);
|
199
|
+
html += this.#getListSectionHTML(
|
200
|
+
this.#getSynonyms(),
|
201
|
+
"Synonyms",
|
202
|
+
"synonyms",
|
203
|
+
);
|
204
|
+
html += "</div>";
|
205
|
+
|
206
|
+
const photos = this.#taxon.getPhotos();
|
207
|
+
if (photos.length > 0) {
|
208
|
+
let photosHtml = "";
|
209
|
+
for (const photo of photos) {
|
210
|
+
photosHtml += `
|
202
211
|
<figure class="col">
|
203
212
|
<a href="${photo.getSourceUrl()}">
|
204
213
|
<img
|
@@ -213,27 +222,27 @@ class PageTaxon extends GenericPage {
|
|
213
222
|
</figcaption>
|
214
223
|
</figure>
|
215
224
|
`;
|
216
|
-
|
217
|
-
|
225
|
+
}
|
226
|
+
html += `
|
218
227
|
<h2>Photos</h2>
|
219
228
|
<div class="row">
|
220
229
|
${photosHtml}
|
221
230
|
</div>
|
222
231
|
`;
|
223
|
-
|
232
|
+
}
|
224
233
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
+
const footerTextPath =
|
235
|
+
Config.getPackageDir() +
|
236
|
+
"/data/text/" +
|
237
|
+
this.getBaseFileName() +
|
238
|
+
".footer.md";
|
239
|
+
const footerMarkdown = Markdown.fileToHTML(footerTextPath);
|
240
|
+
if (footerMarkdown) {
|
241
|
+
html += HTML.wrap("div", footerMarkdown, "section");
|
242
|
+
}
|
234
243
|
|
235
|
-
|
236
|
-
|
244
|
+
this.writeFile(html);
|
245
|
+
}
|
237
246
|
}
|
238
247
|
|
239
248
|
export { PageTaxon };
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ca-plant-list/ca-plant-list",
|
3
|
-
"version": "0.4.
|
3
|
+
"version": "0.4.9",
|
4
4
|
"description": "Tools to create Jekyll files for a website listing plants in an area of California.",
|
5
5
|
"license": "MIT",
|
6
6
|
"repository": {
|
@@ -15,7 +15,8 @@
|
|
15
15
|
"types": "./lib/index.d.ts",
|
16
16
|
"bin": {
|
17
17
|
"ca-plant-list": "scripts/build-site.js",
|
18
|
-
"ca-plant-book": "scripts/build-ebook.js"
|
18
|
+
"ca-plant-book": "scripts/build-ebook.js",
|
19
|
+
"photo-tools": "scripts/photos.js"
|
19
20
|
},
|
20
21
|
"dependencies": {
|
21
22
|
"archiver": "^5.3.1",
|
@@ -25,7 +26,7 @@
|
|
25
26
|
"csv-stringify": "^6.5.1",
|
26
27
|
"image-size": "^1.1.1",
|
27
28
|
"markdown-it": "^14.1.0",
|
28
|
-
"sharp": "^0.
|
29
|
+
"sharp": "^0.33.5",
|
29
30
|
"svgo-ll": "^5.6.0",
|
30
31
|
"unzipper": "^0.10.11"
|
31
32
|
},
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
import path from "path";
|
4
|
+
import { ErrorLog } from "../lib/errorlog.js";
|
5
|
+
import { Program } from "../lib/program.js";
|
6
|
+
import { Taxa } from "../lib/taxa.js";
|
7
|
+
|
8
|
+
const OPT_LOADER = "loader";
|
9
|
+
|
10
|
+
const MAX_PHOTOS = 5;
|
11
|
+
|
12
|
+
/**
|
13
|
+
* @param {import("commander").Command} program
|
14
|
+
* @param {import("commander").OptionValues} options
|
15
|
+
*/
|
16
|
+
async function photos(program, options) {
|
17
|
+
const taxa = await getTaxa(options);
|
18
|
+
const errorLog = new ErrorLog(options.outputdir + "/log.tsv", true);
|
19
|
+
|
20
|
+
auditTaxaWithoutMaxPhotos(errorLog, taxa);
|
21
|
+
|
22
|
+
errorLog.write();
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @param {ErrorLog} errorLog
|
27
|
+
* @param {Taxa} taxa
|
28
|
+
*/
|
29
|
+
function auditTaxaWithoutMaxPhotos(errorLog, taxa) {
|
30
|
+
for (const taxon of taxa.getTaxonList()) {
|
31
|
+
const photos = taxon.getPhotos();
|
32
|
+
if (photos.length !== MAX_PHOTOS) {
|
33
|
+
errorLog.log(taxon.getName(), photos.length.toString());
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* @param {import("commander").OptionValues} options
|
40
|
+
* @return {Promise<Taxa>}
|
41
|
+
*/
|
42
|
+
async function getTaxa(options) {
|
43
|
+
const errorLog = new ErrorLog(options.outputdir + "/errors.tsv", true);
|
44
|
+
|
45
|
+
const loader = options[OPT_LOADER];
|
46
|
+
let taxa;
|
47
|
+
if (loader) {
|
48
|
+
const taxaLoaderClass = await import("file:" + path.resolve(loader));
|
49
|
+
taxa = await taxaLoaderClass.TaxaLoader.loadTaxa(options, errorLog);
|
50
|
+
} else {
|
51
|
+
taxa = new Taxa(
|
52
|
+
Program.getIncludeList(options.datadir),
|
53
|
+
errorLog,
|
54
|
+
options.showFlowerErrors,
|
55
|
+
);
|
56
|
+
}
|
57
|
+
|
58
|
+
errorLog.write();
|
59
|
+
return taxa;
|
60
|
+
}
|
61
|
+
|
62
|
+
const program = Program.getProgram();
|
63
|
+
program.option(
|
64
|
+
"--loader <path>",
|
65
|
+
"The path (relative to the current directory) of the JavaScript file containing the TaxaLoader class. If not provided, the default TaxaLoader will be used.",
|
66
|
+
);
|
67
|
+
program.action((options) => photos(program, options));
|
68
|
+
await program.parseAsync();
|
package/types/classes.d.ts
CHANGED
@@ -9,7 +9,7 @@ declare class Config {
|
|
9
9
|
prefix: string,
|
10
10
|
name: string,
|
11
11
|
subcategory?: string,
|
12
|
-
defaultValue?: string
|
12
|
+
defaultValue?: string,
|
13
13
|
): string | undefined;
|
14
14
|
getCountyCodes(): string[];
|
15
15
|
getLabel(name: string, dflt: string): string;
|
@@ -55,10 +55,6 @@ declare class GlossaryEntry {
|
|
55
55
|
getTermName(): string;
|
56
56
|
}
|
57
57
|
|
58
|
-
declare class Images {
|
59
|
-
getTaxonImages(name: string): TaxonImage[];
|
60
|
-
}
|
61
|
-
|
62
58
|
declare class InatObsOptions {
|
63
59
|
coords?: [number, number];
|
64
60
|
project_id?: string;
|
@@ -72,7 +68,7 @@ declare class SiteGenerator {
|
|
72
68
|
writeTemplate(
|
73
69
|
content: string,
|
74
70
|
attributes: Record<string, string>,
|
75
|
-
filename: string
|
71
|
+
filename: string,
|
76
72
|
): void;
|
77
73
|
}
|
78
74
|
|
@@ -91,7 +87,7 @@ declare class Taxa {
|
|
91
87
|
|
92
88
|
declare class TaxaCol {
|
93
89
|
class?: string;
|
94
|
-
data:
|
90
|
+
data: (taxon: Taxon) => string;
|
95
91
|
title: string;
|
96
92
|
}
|
97
93
|
|
@@ -112,7 +108,7 @@ declare class Taxon {
|
|
112
108
|
getGenusName(): string;
|
113
109
|
getHTMLLink(
|
114
110
|
href: boolean | string | undefined,
|
115
|
-
includeRPI?: boolean
|
111
|
+
includeRPI?: boolean,
|
116
112
|
): string;
|
117
113
|
getINatID(): string;
|
118
114
|
getINatName(): string;
|
@@ -149,19 +145,16 @@ declare class TaxonData {
|
|
149
145
|
taxon_name: string;
|
150
146
|
}
|
151
147
|
|
152
|
-
|
153
|
-
getCaption(): string | undefined;
|
154
|
-
getSrc(): string;
|
155
|
-
}
|
156
|
-
|
157
|
-
type PhotoRights = "CC0"| "CC BY"| "CC BY-NC"| "C"|null;
|
148
|
+
type PhotoRights = "CC0" | "CC BY" | "CC BY-NC" | "C" | null;
|
158
149
|
|
159
150
|
declare class Photo {
|
160
151
|
url?: string;
|
161
152
|
rightsHolder: null | string;
|
162
153
|
rights?: PhotoRights;
|
163
|
-
|
164
|
-
|
154
|
+
getExt(): string;
|
155
|
+
getId(): number;
|
156
|
+
getUrl(): string;
|
157
|
+
getSourceUrl(): string;
|
165
158
|
}
|
166
159
|
|
167
160
|
declare class InatPhoto extends Photo {
|
@@ -169,7 +162,8 @@ declare class InatPhoto extends Photo {
|
|
169
162
|
ext: string;
|
170
163
|
}
|
171
164
|
|
172
|
-
type InatLicenseCode =
|
165
|
+
type InatLicenseCode =
|
166
|
+
| "cc-by-nc-sa"
|
173
167
|
| "cc-by-nc"
|
174
168
|
| "cc-by-nc-nd"
|
175
169
|
| "cc-by"
|
@@ -193,8 +187,8 @@ declare class InatApiTaxon {
|
|
193
187
|
photo: {
|
194
188
|
id: number;
|
195
189
|
attribution: string;
|
196
|
-
license_code: InatLicenseCode
|
190
|
+
license_code: InatLicenseCode;
|
197
191
|
medium_url: string;
|
198
|
-
}
|
199
|
-
}[]
|
192
|
+
};
|
193
|
+
}[];
|
200
194
|
}
|
package/data/photos.csv
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
taxon_name,source,credit
|
2
|
-
Calochortus argillosus,https://inaturalist-open-data.s3.amazonaws.com/photos/210002711/original.jpg,"(c) skfork, some rights reserved (CC BY-NC)"
|
3
|
-
Calochortus luteus,https://inaturalist-open-data.s3.amazonaws.com/photos/257812293/original.jpg,"(c) eeneill, some rights reserved (CC BY-NC)"
|
4
|
-
Calochortus venustus,https://inaturalist-open-data.s3.amazonaws.com/photos/268338027/original.jpg,"(c) Gena Bentall, some rights reserved (CC BY-NC)"
|
5
|
-
Ceanothus cuneatus,https://inaturalist-open-data.s3.amazonaws.com/photos/266280254/original.jpg,"(c) Ixchel Gonzalez-Ramirez, some rights reserved (CC BY-NC)"
|
6
|
-
Claytonia gypsophiloides,https://inaturalist-open-data.s3.amazonaws.com/photos/268277390/original.jpeg,"(c) Christian Naventi, some rights reserved (CC BY-NC)"
|
7
|
-
Lithophragma heterophyllum,https://inaturalist-open-data.s3.amazonaws.com/photos/104408/medium.jpg,"(c) dloarie, some rights reserved (CC BY)"
|
8
|
-
Pseudotsuga menziesii var. menziesii,https://inaturalist-open-data.s3.amazonaws.com/photos/214823452/original.jpeg
|
9
|
-
Pseudotsuga menziesii var. menziesii,https://inaturalist-open-data.s3.amazonaws.com/photos/243900174/original.jpg,"(c) Alan Siegel, some rights reserved (CC BY-NC)"
|
package/lib/ebook/taxonimage.js
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
class TaxonImage {
|
2
|
-
#src;
|
3
|
-
#credit;
|
4
|
-
|
5
|
-
/**
|
6
|
-
* @param {string} src
|
7
|
-
* @param {string} credit
|
8
|
-
*/
|
9
|
-
constructor(src, credit) {
|
10
|
-
this.#src = src;
|
11
|
-
this.#credit = credit;
|
12
|
-
}
|
13
|
-
|
14
|
-
getCaption() {
|
15
|
-
return this.#credit ? this.#credit : undefined;
|
16
|
-
}
|
17
|
-
|
18
|
-
getSrc() {
|
19
|
-
return this.#src;
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
export { TaxonImage };
|