@jjlmoya/utils-nature 1.20.0 → 1.22.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/package.json +1 -1
- package/src/category/index.ts +3 -2
- package/src/entries.ts +5 -1
- package/src/index.ts +4 -0
- package/src/pages/[locale]/[slug].astro +5 -4
- package/src/tests/diacritics_density.test.ts +1 -1
- package/src/tests/inverted_punctuation.test.ts +1 -1
- package/src/tests/script_density.test.ts +1 -1
- package/src/tests/seo_length.test.ts +1 -0
- package/src/tests/seo_translation_completeness.test.ts +69 -0
- package/src/tests/title_quality.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +2 -3
- package/src/tests/translation_copy.test.ts +2 -2
- package/src/tool/compostBinVolumeRatioCalculator/bibliography.astro +18 -0
- package/src/tool/compostBinVolumeRatioCalculator/bibliography.ts +12 -0
- package/src/tool/compostBinVolumeRatioCalculator/component.astro +77 -0
- package/src/tool/compostBinVolumeRatioCalculator/compost-bin-volume-ratio-calculator.css +509 -0
- package/src/tool/compostBinVolumeRatioCalculator/controller.ts +189 -0
- package/src/tool/compostBinVolumeRatioCalculator/dom-views.ts +162 -0
- package/src/tool/compostBinVolumeRatioCalculator/entry.ts +28 -0
- package/src/tool/compostBinVolumeRatioCalculator/evaluator.ts +26 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/de.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/en.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/es.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/fr.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/id.ts +185 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/it.ts +193 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/ja.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/ko.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/nl.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/pl.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/pt.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/ru.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/sv.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/tr.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/i18n/zh.ts +190 -0
- package/src/tool/compostBinVolumeRatioCalculator/index.ts +11 -0
- package/src/tool/compostBinVolumeRatioCalculator/logic.test.ts +55 -0
- package/src/tool/compostBinVolumeRatioCalculator/logic.ts +165 -0
- package/src/tool/compostBinVolumeRatioCalculator/seo.astro +23 -0
- package/src/tool/compostBinVolumeRatioCalculator/storage.ts +25 -0
- package/src/tool/compostBinVolumeRatioCalculator/ui.ts +54 -0
- package/src/tool/cricketThermometer/component.astro +1 -1
- package/src/tool/cricketThermometer/i18n/de.ts +2 -2
- package/src/tool/cricketThermometer/i18n/en.ts +2 -2
- package/src/tool/cricketThermometer/i18n/es.ts +2 -2
- package/src/tool/cricketThermometer/i18n/fr.ts +2 -2
- package/src/tool/cricketThermometer/i18n/id.ts +2 -2
- package/src/tool/cricketThermometer/i18n/it.ts +2 -2
- package/src/tool/cricketThermometer/i18n/ja.ts +2 -2
- package/src/tool/cricketThermometer/i18n/ko.ts +2 -2
- package/src/tool/cricketThermometer/i18n/nl.ts +2 -2
- package/src/tool/cricketThermometer/i18n/pl.ts +2 -2
- package/src/tool/cricketThermometer/i18n/pt.ts +2 -2
- package/src/tool/cricketThermometer/i18n/ru.ts +2 -2
- package/src/tool/cricketThermometer/i18n/sv.ts +2 -2
- package/src/tool/cricketThermometer/i18n/tr.ts +2 -2
- package/src/tool/cricketThermometer/i18n/zh.ts +2 -2
- package/src/tool/cricketThermometer/index.ts +1 -0
- package/src/tool/digitalCarbon/component.astro +3 -3
- package/src/tool/digitalCarbon/i18n/de.ts +2 -2
- package/src/tool/digitalCarbon/i18n/en.ts +2 -2
- package/src/tool/digitalCarbon/i18n/es.ts +2 -2
- package/src/tool/digitalCarbon/i18n/fr.ts +2 -2
- package/src/tool/digitalCarbon/i18n/id.ts +2 -2
- package/src/tool/digitalCarbon/i18n/it.ts +2 -2
- package/src/tool/digitalCarbon/i18n/ja.ts +2 -2
- package/src/tool/digitalCarbon/i18n/ko.ts +2 -2
- package/src/tool/digitalCarbon/i18n/nl.ts +2 -2
- package/src/tool/digitalCarbon/i18n/pl.ts +2 -2
- package/src/tool/digitalCarbon/i18n/pt.ts +2 -2
- package/src/tool/digitalCarbon/i18n/ru.ts +2 -2
- package/src/tool/digitalCarbon/i18n/sv.ts +2 -2
- package/src/tool/digitalCarbon/i18n/tr.ts +2 -2
- package/src/tool/digitalCarbon/i18n/zh.ts +2 -2
- package/src/tool/digitalCarbon/index.ts +1 -0
- package/src/tool/rainHarvester/i18n/de.ts +2 -2
- package/src/tool/rainHarvester/i18n/en.ts +2 -2
- package/src/tool/rainHarvester/i18n/es.ts +2 -2
- package/src/tool/rainHarvester/i18n/fr.ts +2 -2
- package/src/tool/rainHarvester/i18n/id.ts +2 -2
- package/src/tool/rainHarvester/i18n/it.ts +2 -2
- package/src/tool/rainHarvester/i18n/ja.ts +2 -2
- package/src/tool/rainHarvester/i18n/ko.ts +2 -2
- package/src/tool/rainHarvester/i18n/nl.ts +2 -2
- package/src/tool/rainHarvester/i18n/pl.ts +2 -2
- package/src/tool/rainHarvester/i18n/pt.ts +2 -2
- package/src/tool/rainHarvester/i18n/ru.ts +2 -2
- package/src/tool/rainHarvester/i18n/sv.ts +2 -2
- package/src/tool/rainHarvester/i18n/tr.ts +2 -2
- package/src/tool/rainHarvester/i18n/zh.ts +2 -2
- package/src/tool/rainHarvester/index.ts +1 -0
- package/src/tool/seedCalculator/i18n/de.ts +2 -2
- package/src/tool/seedCalculator/i18n/en.ts +2 -2
- package/src/tool/seedCalculator/i18n/es.ts +2 -2
- package/src/tool/seedCalculator/i18n/fr.ts +2 -2
- package/src/tool/seedCalculator/i18n/id.ts +2 -2
- package/src/tool/seedCalculator/i18n/it.ts +2 -2
- package/src/tool/seedCalculator/i18n/ja.ts +2 -2
- package/src/tool/seedCalculator/i18n/ko.ts +2 -2
- package/src/tool/seedCalculator/i18n/nl.ts +2 -2
- package/src/tool/seedCalculator/i18n/pl.ts +2 -2
- package/src/tool/seedCalculator/i18n/pt.ts +2 -2
- package/src/tool/seedCalculator/i18n/ru.ts +2 -2
- package/src/tool/seedCalculator/i18n/sv.ts +2 -2
- package/src/tool/seedCalculator/i18n/tr.ts +2 -2
- package/src/tool/seedCalculator/i18n/zh.ts +2 -2
- package/src/tool/seedCalculator/index.ts +1 -0
- package/src/tool/urbanGardenPlanner/bibliography.astro +9 -0
- package/src/tool/urbanGardenPlanner/bibliography.ts +16 -0
- package/src/tool/urbanGardenPlanner/component.astro +131 -0
- package/src/tool/urbanGardenPlanner/controller.ts +88 -0
- package/src/tool/urbanGardenPlanner/dom-views.ts +84 -0
- package/src/tool/urbanGardenPlanner/entry.ts +29 -0
- package/src/tool/urbanGardenPlanner/evaluator.ts +27 -0
- package/src/tool/urbanGardenPlanner/i18n/de.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/en.ts +179 -0
- package/src/tool/urbanGardenPlanner/i18n/es.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/fr.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/id.ts +50 -0
- package/src/tool/urbanGardenPlanner/i18n/it.ts +45 -0
- package/src/tool/urbanGardenPlanner/i18n/ja.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/ko.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/nl.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/pl.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/pt.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/ru.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/sv.ts +39 -0
- package/src/tool/urbanGardenPlanner/i18n/tr.ts +104 -0
- package/src/tool/urbanGardenPlanner/i18n/zh.ts +104 -0
- package/src/tool/urbanGardenPlanner/index.ts +11 -0
- package/src/tool/urbanGardenPlanner/logic.test.ts +45 -0
- package/src/tool/urbanGardenPlanner/logic.ts +55 -0
- package/src/tool/urbanGardenPlanner/seo.astro +15 -0
- package/src/tool/urbanGardenPlanner/storage.ts +25 -0
- package/src/tool/urbanGardenPlanner/ui.ts +38 -0
- package/src/tool/urbanGardenPlanner/urban-garden-rainwater-and-soil-planner.css +531 -0
- package/src/tools.ts +5 -2
- package/src/types.ts +4 -4
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { CompostBinVolumeRatioCalculatorUI } from "./ui";
|
|
2
|
+
import type {
|
|
3
|
+
CompostInputs,
|
|
4
|
+
CompostResult,
|
|
5
|
+
MoistureLevel,
|
|
6
|
+
UnitSystem,
|
|
7
|
+
} from "./logic";
|
|
8
|
+
import { getDiagnostics } from "./evaluator";
|
|
9
|
+
|
|
10
|
+
function number(value: number, maximumFractionDigits = 1): string {
|
|
11
|
+
return new Intl.NumberFormat("en-US", { maximumFractionDigits }).format(
|
|
12
|
+
value,
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function unitLabels(
|
|
17
|
+
unitSystem: UnitSystem,
|
|
18
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
19
|
+
): { volume: string; dimension: string } {
|
|
20
|
+
return unitSystem === "metric"
|
|
21
|
+
? { volume: ui.volumeUnitLiters, dimension: ui.dimensionUnitCm }
|
|
22
|
+
: { volume: ui.volumeUnitGallons, dimension: ui.dimensionUnitIn };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function displayVolume(valueLiters: number, unitSystem: UnitSystem): number {
|
|
26
|
+
return unitSystem === "imperial" ? valueLiters / 3.785411784 : valueLiters;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function moistureLabel(
|
|
30
|
+
level: MoistureLevel,
|
|
31
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
32
|
+
): string {
|
|
33
|
+
if (level === "dry") return ui.moistureAdviceDry;
|
|
34
|
+
if (level === "wet") return ui.moistureAdviceWet;
|
|
35
|
+
return ui.moistureAdviceSponge;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function statusLabel(
|
|
39
|
+
key: string,
|
|
40
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
41
|
+
): string {
|
|
42
|
+
const labels: Record<string, string> = {
|
|
43
|
+
balanced: ui.statusBalanced,
|
|
44
|
+
"too-green": ui.statusTooGreen,
|
|
45
|
+
"too-brown": ui.statusTooBrown,
|
|
46
|
+
"no-greens": ui.statusNoGreens,
|
|
47
|
+
overfilled: ui.statusOverfilled,
|
|
48
|
+
dry: ui.statusDry,
|
|
49
|
+
wet: ui.statusWet,
|
|
50
|
+
};
|
|
51
|
+
return labels[key] ?? ui.statusGoodMoisture;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function layerMarkup(result: CompostResult): string {
|
|
55
|
+
const total = result.materialsLiters;
|
|
56
|
+
if (total <= 0)
|
|
57
|
+
return '<text class="compost-scene-empty" x="300" y="218">Add materials to build the pile</text>';
|
|
58
|
+
const brownShare =
|
|
59
|
+
result.ratio === null ? 0.5 : result.ratio / (result.ratio + 1);
|
|
60
|
+
const layers = 8;
|
|
61
|
+
const bottom = 358;
|
|
62
|
+
const layerHeight = 34;
|
|
63
|
+
return Array.from({ length: layers }, (_, index) => {
|
|
64
|
+
const y = bottom - (index + 1) * layerHeight;
|
|
65
|
+
const isBrown = index / layers < brownShare;
|
|
66
|
+
const className = isBrown
|
|
67
|
+
? "compost-layer compost-layer-brown"
|
|
68
|
+
: "compost-layer compost-layer-green";
|
|
69
|
+
const opacity = Math.max(0.35, 1 - Math.abs(index - 4) * 0.06);
|
|
70
|
+
return `<rect class="${className}" x="164" y="${y}" width="272" height="${layerHeight + 1}" opacity="${opacity.toFixed(2)}" />`;
|
|
71
|
+
}).join("");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function sceneMarkup(
|
|
75
|
+
inputs: CompostInputs,
|
|
76
|
+
result: CompostResult,
|
|
77
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
78
|
+
): string {
|
|
79
|
+
const fill = Math.min(100, Math.max(0, result.fillPercent));
|
|
80
|
+
const fillHeight = 312 * (fill / 100);
|
|
81
|
+
const fillY = 358 - fillHeight;
|
|
82
|
+
const shapeLabel =
|
|
83
|
+
inputs.shape === "rectangular" ? ui.shapeRectangular : ui.shapeCylindrical;
|
|
84
|
+
return `<div class="compost-scene-heading"><span>${ui.sceneTitle}</span><strong>${shapeLabel}</strong></div><svg class="compost-scene-svg" viewBox="0 0 600 420" role="img" aria-label="${ui.sceneTitle}"><path class="compost-scene-sun" d="M76 80c46-48 115-48 162 0" /><path class="compost-scene-ground" d="M42 370c112-23 197-14 282 0 89 15 171 14 234-6" /><rect class="compost-bin" x="145" y="42" width="310" height="328" rx="26" /><clipPath id="compost-clip"><rect x="164" y="58" width="272" height="300" rx="17" /></clipPath><g clip-path="url(#compost-clip)"><rect class="compost-fill" x="164" y="${fillY.toFixed(1)}" width="272" height="${fillHeight.toFixed(1)}" /><g>${layerMarkup(result)}</g></g><path class="compost-scene-rim" d="M164 58h272" /><path class="compost-scene-marker" d="M478 358h31M478 58h31M494 358V58" /><text class="compost-scene-scale" x="519" y="214">${number(displayVolume(result.capacityLiters, inputs.unitSystem))} ${unitLabels(inputs.unitSystem, ui).volume}</text><text class="compost-scene-scale" x="519" y="232">${number(result.fillPercent, 0)}% full</text><text class="compost-scene-label compost-scene-label-brown" x="87" y="156">${ui.brownLabel}</text><text class="compost-scene-label compost-scene-label-green" x="87" y="176">${ui.greenLabel}</text></svg>`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function actionText(
|
|
88
|
+
inputs: CompostInputs,
|
|
89
|
+
result: CompostResult,
|
|
90
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
91
|
+
): string {
|
|
92
|
+
const ratioText =
|
|
93
|
+
result.ratio === null ? ui.statusNoGreens : `${number(result.ratio, 2)}:1`;
|
|
94
|
+
const moistureText = moistureLabel(inputs.moisture, ui);
|
|
95
|
+
let tone = "caution";
|
|
96
|
+
if (result.status === "balanced") tone = "good";
|
|
97
|
+
if (result.status === "overfilled") tone = "alert";
|
|
98
|
+
const airText =
|
|
99
|
+
result.status === "overfilled" ? ui.statusOverfilled : ui.statusNote;
|
|
100
|
+
return `<div class="compost-result-status" data-tone="${tone}"><span>${statusLabel(result.status, ui)}</span><strong>${ratioText}</strong></div><div class="compost-result-advice"><p><b>${ui.brownTarget}</b> ${number(displayVolume(result.targetBrownLowLiters, inputs.unitSystem))} to ${number(displayVolume(result.targetBrownHighLiters, inputs.unitSystem))} ${unitLabels(inputs.unitSystem, ui).volume}</p><p><b>${ui.waterAction}</b> ${moistureText}</p><p><b>${ui.airAction}</b> ${airText}</p></div>`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function renderCompost(
|
|
104
|
+
root: HTMLElement,
|
|
105
|
+
inputs: CompostInputs,
|
|
106
|
+
result: CompostResult,
|
|
107
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
108
|
+
): void {
|
|
109
|
+
const labels = unitLabels(inputs.unitSystem, ui);
|
|
110
|
+
const scene = root.querySelector<HTMLElement>("[data-compost-scene]");
|
|
111
|
+
const results = root.querySelector<HTMLElement>("[data-compost-results]");
|
|
112
|
+
const diagnostics = getDiagnostics(result);
|
|
113
|
+
if (scene) scene.innerHTML = sceneMarkup(inputs, result, ui);
|
|
114
|
+
if (results) {
|
|
115
|
+
results.innerHTML = `<div class="compost-result-eyebrow">${ui.resultCapacity}</div><div class="compost-result-capacity">${number(displayVolume(result.capacityLiters, inputs.unitSystem))} <span>${labels.volume}</span></div><div class="compost-result-stats"><div><span>${ui.resultMaterials}</span><strong>${number(displayVolume(result.materialsLiters, inputs.unitSystem))} ${labels.volume}</strong></div><div><span>${ui.resultRatio}</span><strong>${result.ratio === null ? "..." : `${number(result.ratio, 2)}:1`}</strong></div><div><span>${ui.resultFill}</span><strong>${number(result.fillPercent, 0)}%</strong></div></div>${actionText(inputs, result, ui)}<div class="compost-result-diagnostics">${diagnostics.map((item) => `<span data-tone="${item.tone}">${statusLabel(item.key, ui)}</span>`).join("")}</div>`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function syncInputLabels(
|
|
120
|
+
root: HTMLElement,
|
|
121
|
+
inputs: CompostInputs,
|
|
122
|
+
ui: CompostBinVolumeRatioCalculatorUI,
|
|
123
|
+
): void {
|
|
124
|
+
const labels = unitLabels(inputs.unitSystem, ui);
|
|
125
|
+
syncUnitText(root, labels);
|
|
126
|
+
syncPressedStates(root, inputs);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function syncUnitText(
|
|
130
|
+
root: HTMLElement,
|
|
131
|
+
labels: { volume: string; dimension: string },
|
|
132
|
+
): void {
|
|
133
|
+
root
|
|
134
|
+
.querySelectorAll<HTMLElement>("[data-dimension-unit]")
|
|
135
|
+
.forEach((node) => {
|
|
136
|
+
node.textContent = labels.dimension;
|
|
137
|
+
});
|
|
138
|
+
root.querySelectorAll<HTMLElement>("[data-volume-unit]").forEach((node) => {
|
|
139
|
+
node.textContent = labels.volume;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function syncPressedStates(root: HTMLElement, inputs: CompostInputs): void {
|
|
144
|
+
root
|
|
145
|
+
.querySelector<HTMLElement>("[data-unit-metric]")
|
|
146
|
+
?.toggleAttribute("aria-pressed", inputs.unitSystem === "metric");
|
|
147
|
+
root
|
|
148
|
+
.querySelector<HTMLElement>("[data-unit-imperial]")
|
|
149
|
+
?.toggleAttribute("aria-pressed", inputs.unitSystem === "imperial");
|
|
150
|
+
root
|
|
151
|
+
.querySelector<HTMLElement>("[data-shape-rectangular]")
|
|
152
|
+
?.toggleAttribute("aria-pressed", inputs.shape === "rectangular");
|
|
153
|
+
root
|
|
154
|
+
.querySelector<HTMLElement>("[data-shape-cylindrical]")
|
|
155
|
+
?.toggleAttribute("aria-pressed", inputs.shape === "cylindrical");
|
|
156
|
+
root.querySelectorAll<HTMLElement>("[data-moisture]").forEach((node) => {
|
|
157
|
+
node.toggleAttribute(
|
|
158
|
+
"aria-pressed",
|
|
159
|
+
node.dataset.moisture === inputs.moisture,
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { NatureToolEntry, ToolLocaleContent } from "../../types";
|
|
2
|
+
import type { CompostBinVolumeRatioCalculatorUI } from "./ui";
|
|
3
|
+
|
|
4
|
+
export type CompostBinVolumeRatioCalculatorLocaleContent =
|
|
5
|
+
ToolLocaleContent<CompostBinVolumeRatioCalculatorUI>;
|
|
6
|
+
|
|
7
|
+
export const compostBinVolumeRatioCalculator: NatureToolEntry<CompostBinVolumeRatioCalculatorUI> =
|
|
8
|
+
{
|
|
9
|
+
id: "compost-bin-volume-ratio-calculator",
|
|
10
|
+
icons: { bg: "mdi:compost", fg: "mdi:leaf" },
|
|
11
|
+
i18n: {
|
|
12
|
+
de: async () => (await import("./i18n/de")).content,
|
|
13
|
+
en: async () => (await import("./i18n/en")).content,
|
|
14
|
+
es: async () => (await import("./i18n/es")).content,
|
|
15
|
+
fr: async () => (await import("./i18n/fr")).content,
|
|
16
|
+
id: async () => (await import("./i18n/id")).content,
|
|
17
|
+
it: async () => (await import("./i18n/it")).content,
|
|
18
|
+
ja: async () => (await import("./i18n/ja")).content,
|
|
19
|
+
ko: async () => (await import("./i18n/ko")).content,
|
|
20
|
+
nl: async () => (await import("./i18n/nl")).content,
|
|
21
|
+
pl: async () => (await import("./i18n/pl")).content,
|
|
22
|
+
pt: async () => (await import("./i18n/pt")).content,
|
|
23
|
+
ru: async () => (await import("./i18n/ru")).content,
|
|
24
|
+
sv: async () => (await import("./i18n/sv")).content,
|
|
25
|
+
tr: async () => (await import("./i18n/tr")).content,
|
|
26
|
+
zh: async () => (await import("./i18n/zh")).content,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CompostResult } from "./logic";
|
|
2
|
+
|
|
3
|
+
export type DiagnosticTone = "good" | "caution" | "alert";
|
|
4
|
+
|
|
5
|
+
export interface CompostDiagnostic {
|
|
6
|
+
key: string;
|
|
7
|
+
tone: DiagnosticTone;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getDiagnostics(result: CompostResult): CompostDiagnostic[] {
|
|
11
|
+
const diagnostics: CompostDiagnostic[] = [
|
|
12
|
+
{
|
|
13
|
+
key: result.status,
|
|
14
|
+
tone: result.status === "balanced" ? "good" : "caution",
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
if (result.moistureStatus !== "good") {
|
|
18
|
+
diagnostics.push({
|
|
19
|
+
key: result.moistureStatus,
|
|
20
|
+
tone: result.moistureStatus === "dry" ? "caution" : "alert",
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (result.status === "overfilled")
|
|
24
|
+
diagnostics[0] = { key: result.status, tone: "alert" };
|
|
25
|
+
return diagnostics;
|
|
26
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FAQPage,
|
|
3
|
+
HowTo,
|
|
4
|
+
SoftwareApplication,
|
|
5
|
+
WithContext,
|
|
6
|
+
} from "schema-dts";
|
|
7
|
+
import { bibliography } from "../bibliography";
|
|
8
|
+
import type { CompostBinVolumeRatioCalculatorLocaleContent } from "../entry";
|
|
9
|
+
|
|
10
|
+
const slug = "komposter-volumen-braun-gruen-verhaeltnis-rechner";
|
|
11
|
+
const title = "Komposter Volumen und Braun Grün Verhältnis Rechner";
|
|
12
|
+
const description =
|
|
13
|
+
"Berechnen Sie das Innenvolumen eines rechteckigen oder zylindrischen Komposters und prüfen Sie das praktische Verhältnis von Braunstoffen, Grünstoffen, Feuchtigkeit und Belüftung.";
|
|
14
|
+
|
|
15
|
+
const faq = [
|
|
16
|
+
{
|
|
17
|
+
question: "Wie berechnet man das Volumen eines Komposters?",
|
|
18
|
+
answer:
|
|
19
|
+
"Messen Sie den Innenraum des Behälters. Bei einem rechteckigen Komposter multiplizieren Sie Breite, Tiefe und Höhe und rechnen Kubikzentimeter in Liter um. Bei einem Zylinder nutzen Sie Pi mal Radius zum Quadrat mal Höhe.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
question: "Was ist das richtige Verhältnis von Braunstoffen zu Grünstoffen?",
|
|
23
|
+
answer:
|
|
24
|
+
"Ein praktischer Richtwert sind zwei bis drei Teile kohlenstoffreiche Braunstoffe nach Volumen auf einen Teil stickstoffreiche Grünstoffe. Passen Sie die Mischung an Feuchtigkeit, Geruch und Durchlüftung an.",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
question: "Wie viel Kompost passt in den Behälter?",
|
|
28
|
+
answer:
|
|
29
|
+
"Vergleichen Sie das Gesamtvolumen Ihres Kompostguts mit dem Innenvolumen des Komposters. Lassen Sie stets ausreichend Raum für Belüftung und das regelmäßige Umschichten des Haufens.",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
question: "Was bedeutet die Feuchtigkeit eines ausgedrückten Schwamms?",
|
|
33
|
+
answer:
|
|
34
|
+
"Das Material sollte sich durchgehend feucht anfühlen, ohne bei leichtem Druck Wasser abzugeben. Trockener Kompost stoppt die mikrobielle Zersetzung, während zu nasser Kompost Luftlöcher verliert.",
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const howTo = [
|
|
39
|
+
{
|
|
40
|
+
name: "Form des Komposters wählen",
|
|
41
|
+
text: "Wählen Sie rechteckig oder zylindrisch und geben Sie die Innenmaße in Zentimetern oder Zoll präzise ein.",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "Materialvolumen eingeben",
|
|
45
|
+
text: "Schätzen Sie das getrennte Volumen von braunen kohlenstoffreichen und grünen stickstoffreichen Abfällen ab.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "Feuchtigkeitsstufe einstellen",
|
|
49
|
+
text: "Wählen Sie trocken, ausgedrückter Schwamm oder nass für passende Pflegetipps und Wartungshinweise.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "Ergebnis auswerten",
|
|
53
|
+
text: "Nutzen Sie Kapazität, Füllstand und Mischungsverhältnis zur Anpassung von Belüftung, Materialzugabe und Feuchte.",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
58
|
+
"@context": "https://schema.org",
|
|
59
|
+
"@type": "FAQPage",
|
|
60
|
+
mainEntity: faq.map((item) => ({
|
|
61
|
+
"@type": "Question",
|
|
62
|
+
name: item.question,
|
|
63
|
+
acceptedAnswer: { "@type": "Answer", text: item.answer },
|
|
64
|
+
})),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const howToSchema: WithContext<HowTo> = {
|
|
68
|
+
"@context": "https://schema.org",
|
|
69
|
+
"@type": "HowTo",
|
|
70
|
+
name: title,
|
|
71
|
+
description,
|
|
72
|
+
step: howTo.map((step, index) => ({
|
|
73
|
+
"@type": "HowToStep",
|
|
74
|
+
position: index + 1,
|
|
75
|
+
name: step.name,
|
|
76
|
+
text: step.text,
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
81
|
+
"@context": "https://schema.org",
|
|
82
|
+
"@type": "SoftwareApplication",
|
|
83
|
+
name: title,
|
|
84
|
+
description,
|
|
85
|
+
applicationCategory: "UtilityApplication",
|
|
86
|
+
operatingSystem: "All",
|
|
87
|
+
offers: { "@type": "Offer", price: "0", priceCurrency: "EUR" },
|
|
88
|
+
inLanguage: "de",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const content: CompostBinVolumeRatioCalculatorLocaleContent = {
|
|
92
|
+
slug,
|
|
93
|
+
title,
|
|
94
|
+
description,
|
|
95
|
+
ui: {
|
|
96
|
+
unitMetric: "Metrisch",
|
|
97
|
+
unitImperial: "Imperial",
|
|
98
|
+
shapeTitle: "Komposterform",
|
|
99
|
+
shapeRectangular: "Rechteckig",
|
|
100
|
+
shapeCylindrical: "Zylindrisch",
|
|
101
|
+
widthLabel: "Innenbreite",
|
|
102
|
+
depthLabel: "Innentiefe",
|
|
103
|
+
diameterLabel: "Innendurchmesser",
|
|
104
|
+
heightLabel: "Innenhöhe",
|
|
105
|
+
brownLabel: "Braunstoffe",
|
|
106
|
+
greenLabel: "Grünstoffe",
|
|
107
|
+
moistureTitle: "Feuchtigkeitsgefühl",
|
|
108
|
+
moistureDry: "Trocken",
|
|
109
|
+
moistureSponge: "Ausgedrückter Schwamm",
|
|
110
|
+
moistureWet: "Nass",
|
|
111
|
+
moistureAdviceDry: "Trocken: Schrittweise befeuchten und umschichten.",
|
|
112
|
+
moistureAdviceSponge: "Optimal: Feuchte wie ein ausgedrückter Schwamm halten.",
|
|
113
|
+
moistureAdviceWet: "Nass: Trockenes Braunmaterial zugeben und wenden.",
|
|
114
|
+
recipeTitle: "Empfohlene Mischung",
|
|
115
|
+
recipeKitchen: "Küchenabfälle",
|
|
116
|
+
recipeGarden: "Gartenabfälle",
|
|
117
|
+
recipeLeafy: "Laubmischung",
|
|
118
|
+
sceneTitle: "Schnitt durch den Komposthaufen",
|
|
119
|
+
resultCapacity: "Innenvolumen des Komposters",
|
|
120
|
+
resultMaterials: "Eingegebenes Material",
|
|
121
|
+
resultRatio: "Verhältnis Braun zu Grün",
|
|
122
|
+
resultFill: "Ausgenutzte Kapazität",
|
|
123
|
+
brownTarget: "Zielmenge Braunstoffe",
|
|
124
|
+
waterAction: "Feuchtigkeit",
|
|
125
|
+
airAction: "Luft und Struktur",
|
|
126
|
+
statusBalanced: "Gutes Startverhältnis",
|
|
127
|
+
statusTooGreen: "Mehr Braunstoffe zugeben",
|
|
128
|
+
statusTooBrown: "Mehr Grünstoffe zugeben",
|
|
129
|
+
statusNoGreens: "Grünstoffe hinzufügen",
|
|
130
|
+
statusOverfilled: "Komposter ist überfüllt",
|
|
131
|
+
statusDry: "Haufen ist zu trocken",
|
|
132
|
+
statusWet: "Haufen ist zu nass",
|
|
133
|
+
statusGoodMoisture: "Feuchtigkeit im optimalen Bereich",
|
|
134
|
+
statusNote: "Haufen regelmäßig umschichten für Belüftung.",
|
|
135
|
+
volumeUnitLiters: "L",
|
|
136
|
+
volumeUnitGallons: "gal",
|
|
137
|
+
dimensionUnitCm: "cm",
|
|
138
|
+
dimensionUnitIn: "in",
|
|
139
|
+
formulaTitle: "Geometrische Volumenberechnung",
|
|
140
|
+
formulaText:
|
|
141
|
+
"Der Rechner ermittelt die echte Innenkapazität aus Ihren Abmessungen. Rechteckige Behälter nutzen Breite × Tiefe × Höhe. Zylindrische Behälter nutzen π × Radius² × Höhe. Alle Volumen werden auf dieselbe Einheit umgerechnet, bevor der Füllstand angezeigt wird.",
|
|
142
|
+
practicalTitle: "Das Verhältnis ist ein Orientierungswert",
|
|
143
|
+
practicalText:
|
|
144
|
+
"Das Braunstoff-Ziel nutzt das Zwei- bis Dreifache des Grünstoffvolumens. Feuchtigkeit und Struktur sind ebenso wichtig: streben Sie ein Schwammgefühl an, erhalten Sie grobe Materialstrukturen und wenden Sie den Haufen bei Verdichtung.",
|
|
145
|
+
localNote:
|
|
146
|
+
"Alle Berechnungen finden lokal im Browser statt. Dies ist eine praktische Planungshilfe für Garten und Kompostierung im Haushalt.",
|
|
147
|
+
resetLabel: "Zurücksetzen",
|
|
148
|
+
},
|
|
149
|
+
seo: [
|
|
150
|
+
{
|
|
151
|
+
type: "title",
|
|
152
|
+
text: "Berechnen Sie das echte Volumen Ihres Komposters",
|
|
153
|
+
level: 2,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
type: "paragraph",
|
|
157
|
+
html: "Ein Komposter-Volumenrechner hilft besonders dann zuverlässig, wenn er auf den tatsächlichen Innenmaßen basiert und nicht auf den äußeren Herstellerangaben. Geben Sie die Breite, Tiefe und Höhe eines rechteckigen Komposters oder den Durchmesser und die Höhe eines zylindrischen Modells ein. Das Ergebnis zeigt die verbleibende Nettokapazität in Litern oder Gallonen und vergleicht diese direkt mit der Menge der geplanten Abfälle.",
|
|
158
|
+
},
|
|
159
|
+
{ type: "title", text: "Mathematische Formeln zur Volumenberechnung", level: 3 },
|
|
160
|
+
{
|
|
161
|
+
type: "paragraph",
|
|
162
|
+
html: "Für rechteckige Komposter gilt die geometrische Formel <code>Breite × Tiefe × Höhe</code>. Wenn Sie die Messungen in Zentimetern durchführen, teilen Sie das Ergebnis in Kubikzentimetern durch 1.000, um das korrekte Volumen in Litern zu erhalten. Für zylindrische Behälter nutzen Sie <code>π × Radius² × Höhe</code>, wobei der Radius der Hälfte des Innendurchmessers entspricht. Messen Sie nur den nutzbaren Innenraum ohne Wandstärken oder Deckel.",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
type: "list",
|
|
166
|
+
items: [
|
|
167
|
+
"<strong>Rechteckiger Behälter:</strong> Breite × Tiefe × Höhe.",
|
|
168
|
+
"<strong>Zylindrischer Behälter:</strong> π × Radius² × Höhe.",
|
|
169
|
+
"<strong>Volumenumrechnung:</strong> 1.000 Kubikzentimeter entsprechen exakt 1 Liter.",
|
|
170
|
+
"<strong>Füllstandsanzeige:</strong> Summe aus Braun- und Grünvolumen im Vergleich zur maximalen Innenkapazität.",
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{ type: "title", text: "Ausgewogenes Verhältnis zwischen Braunstoffen und Grünstoffen", level: 3 },
|
|
174
|
+
{
|
|
175
|
+
type: "paragraph",
|
|
176
|
+
html: "Als bewährter Praxiswert gilt ein Mischungsverhältnis von zwei bis drei Teilen braunen kohlenstoffreichen Materialien auf einen Teil grüner stickstoffreicher Abfälle nach Volumen. Zu den Braunstoffen zählen trockenes Laub, zerkleinerter Karton und kleine Zweige. Grünstoffe umfassen frische Küchenabfälle, Rasenschnitt und Pflanzenteile. Der Rechner gibt den Zielbereich für Braunstoffe an, während die Feuchtigkeit und Durchlüftung den Zersetzungsprozess unterstützen.",
|
|
177
|
+
},
|
|
178
|
+
{ type: "title", text: "Feuchtigkeit und Belüftung richtig steuern", level: 3 },
|
|
179
|
+
{
|
|
180
|
+
type: "paragraph",
|
|
181
|
+
html: "Achten Sie auf die Konsistenz eines feuchten, gut ausgedrückten Schwamms. Zu trockener Kompost verlangsamt die biologische Aktivität der Mikroorganismen erheblich, während ein durchnässter Haufen an Sauerstoff verliert und unangenehme Gerüche entwickeln kann. Durch regelmäßiges Umschichten bringen Sie frischen Sauerstoff in den Komposthaufen.",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
type: "tip",
|
|
185
|
+
title: "Praktischer Nutzungshinweis",
|
|
186
|
+
html: "Dieses Volumenergebnis dient als nützlicher Richtwert für die Gartenpraxis und ersetzt keine chemische Laboranalyse des C:N-Verhältnisses. Beachten Sie stets die lokalen Vorgaben zur Eigenkompostierung.",
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
faq,
|
|
190
|
+
bibliography,
|
|
191
|
+
howTo,
|
|
192
|
+
schemas: [faqSchema, howToSchema, appSchema],
|
|
193
|
+
};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FAQPage,
|
|
3
|
+
HowTo,
|
|
4
|
+
SoftwareApplication,
|
|
5
|
+
WithContext,
|
|
6
|
+
} from "schema-dts";
|
|
7
|
+
import { bibliography } from "../bibliography";
|
|
8
|
+
import type { CompostBinVolumeRatioCalculatorLocaleContent } from "../entry";
|
|
9
|
+
|
|
10
|
+
const slug = "compost-bin-volume-and-browns-greens-ratio-calculator";
|
|
11
|
+
const title = "Compost Bin Volume and Browns Greens Ratio Calculator";
|
|
12
|
+
const description =
|
|
13
|
+
"Calculate the internal volume of a rectangular or cylindrical compost bin and check the practical balance of browns, greens, moisture, and air.";
|
|
14
|
+
|
|
15
|
+
const faq = [
|
|
16
|
+
{
|
|
17
|
+
question: "How do I calculate compost bin volume?",
|
|
18
|
+
answer:
|
|
19
|
+
"Measure the inside of the bin. For a rectangular bin, multiply width by depth by height and convert cubic centimeters to liters. For a cylinder, use pi times the radius squared times height.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
question: "What is the right ratio of browns to greens in compost?",
|
|
23
|
+
answer:
|
|
24
|
+
"A practical starting point is two to three parts carbon rich browns by volume for each part nitrogen rich greens. Adjust by observing moisture, smell, and airflow rather than treating the ratio as a laboratory measurement.",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
question: "How much compost can I put in the bin?",
|
|
28
|
+
answer:
|
|
29
|
+
"Compare the volume of your materials with the bin capacity. Leave room for air and turning, and do not pack the contents tightly just to reach the rim.",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
question: "What does wrung out sponge moisture mean?",
|
|
33
|
+
answer:
|
|
34
|
+
"The materials should feel damp without releasing water when squeezed. A dry pile slows down, while a saturated pile needs more dry structure and turning for airflow.",
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const howTo = [
|
|
39
|
+
{
|
|
40
|
+
name: "Choose the bin shape",
|
|
41
|
+
text: "Select rectangular or cylindrical and enter the inside dimensions in centimeters or inches.",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "Add your material volumes",
|
|
45
|
+
text: "Estimate the separate volume of brown carbon rich materials and green nitrogen rich materials.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "Set the moisture feel",
|
|
49
|
+
text: "Choose dry, wrung out sponge, or wet to make the maintenance advice match the pile you are preparing.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "Read the pile",
|
|
53
|
+
text: "Use the capacity, fill level, ratio, and warnings to decide whether to add browns, add moisture, or turn the pile.",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
58
|
+
"@context": "https://schema.org",
|
|
59
|
+
"@type": "FAQPage",
|
|
60
|
+
mainEntity: faq.map((item) => ({
|
|
61
|
+
"@type": "Question",
|
|
62
|
+
name: item.question,
|
|
63
|
+
acceptedAnswer: { "@type": "Answer", text: item.answer },
|
|
64
|
+
})),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const howToSchema: WithContext<HowTo> = {
|
|
68
|
+
"@context": "https://schema.org",
|
|
69
|
+
"@type": "HowTo",
|
|
70
|
+
name: title,
|
|
71
|
+
description,
|
|
72
|
+
step: howTo.map((step, index) => ({
|
|
73
|
+
"@type": "HowToStep",
|
|
74
|
+
position: index + 1,
|
|
75
|
+
name: step.name,
|
|
76
|
+
text: step.text,
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
81
|
+
"@context": "https://schema.org",
|
|
82
|
+
"@type": "SoftwareApplication",
|
|
83
|
+
name: title,
|
|
84
|
+
description,
|
|
85
|
+
applicationCategory: "UtilityApplication",
|
|
86
|
+
operatingSystem: "All",
|
|
87
|
+
offers: { "@type": "Offer", price: "0", priceCurrency: "EUR" },
|
|
88
|
+
inLanguage: "en",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const content: CompostBinVolumeRatioCalculatorLocaleContent = {
|
|
92
|
+
slug,
|
|
93
|
+
title,
|
|
94
|
+
description,
|
|
95
|
+
ui: {
|
|
96
|
+
unitMetric: "Metric",
|
|
97
|
+
unitImperial: "Imperial",
|
|
98
|
+
shapeTitle: "Bin shape",
|
|
99
|
+
shapeRectangular: "Rectangular",
|
|
100
|
+
shapeCylindrical: "Cylindrical",
|
|
101
|
+
widthLabel: "Inside width",
|
|
102
|
+
depthLabel: "Inside depth",
|
|
103
|
+
diameterLabel: "Inside diameter",
|
|
104
|
+
heightLabel: "Inside height",
|
|
105
|
+
brownLabel: "Browns",
|
|
106
|
+
greenLabel: "Greens",
|
|
107
|
+
moistureTitle: "Moisture feel",
|
|
108
|
+
moistureDry: "Dry",
|
|
109
|
+
moistureSponge: "Wringed sponge",
|
|
110
|
+
moistureWet: "Wet",
|
|
111
|
+
moistureAdviceDry: "Dry: moisten gradually and turn.",
|
|
112
|
+
moistureAdviceSponge: "Good: keep the wrung out sponge feel.",
|
|
113
|
+
moistureAdviceWet: "Wet: add dry browns and turn.",
|
|
114
|
+
recipeTitle: "Add what you have",
|
|
115
|
+
recipeKitchen: "Kitchen caddy",
|
|
116
|
+
recipeGarden: "Garden batch",
|
|
117
|
+
recipeLeafy: "Leafy pile",
|
|
118
|
+
sceneTitle: "Your pile in section",
|
|
119
|
+
resultCapacity: "Internal bin capacity",
|
|
120
|
+
resultMaterials: "Materials entered",
|
|
121
|
+
resultRatio: "Browns to greens",
|
|
122
|
+
resultFill: "Capacity used",
|
|
123
|
+
brownTarget: "Brown target",
|
|
124
|
+
waterAction: "Moisture",
|
|
125
|
+
airAction: "Air and structure",
|
|
126
|
+
statusBalanced: "Good starting balance",
|
|
127
|
+
statusTooGreen: "Add more browns",
|
|
128
|
+
statusTooBrown: "Add more greens",
|
|
129
|
+
statusNoGreens: "Add some greens",
|
|
130
|
+
statusOverfilled: "Pile is over capacity",
|
|
131
|
+
statusDry: "Pile feels dry",
|
|
132
|
+
statusWet: "Pile feels too wet",
|
|
133
|
+
statusGoodMoisture: "Moisture is in range",
|
|
134
|
+
statusNote: "Turn the pile to reopen air pockets.",
|
|
135
|
+
volumeUnitLiters: "L",
|
|
136
|
+
volumeUnitGallons: "gal",
|
|
137
|
+
dimensionUnitCm: "cm",
|
|
138
|
+
dimensionUnitIn: "in",
|
|
139
|
+
formulaTitle: "The volume behind the drawing",
|
|
140
|
+
formulaText:
|
|
141
|
+
"The calculator finds internal capacity from your inside measurements. Rectangular bins use width × depth × height. Cylindrical bins use π × radius² × height. Material volumes are converted to the same unit before the fill level is shown.",
|
|
142
|
+
practicalTitle: "A ratio is a starting point",
|
|
143
|
+
practicalText:
|
|
144
|
+
"The brown target uses two to three times the green volume. Moisture and air still matter: aim for a wrung out sponge feel, keep bulky structure in the mix, and turn the pile when it settles.",
|
|
145
|
+
localNote:
|
|
146
|
+
"All measurements stay in this browser. This is a planning aid, not a laboratory C:N analysis.",
|
|
147
|
+
resetLabel: "Reset",
|
|
148
|
+
},
|
|
149
|
+
seo: [
|
|
150
|
+
{
|
|
151
|
+
type: "title",
|
|
152
|
+
text: "Calculate the Real Capacity of a Compost Bin",
|
|
153
|
+
level: 2,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
type: "paragraph",
|
|
157
|
+
html: "A compost bin volume calculator is most useful when it works from the inside measurements, not the label on the product. Enter the width, depth, and height of a rectangular bin, or the diameter and height of a cylindrical one. The result shows the internal capacity in liters or gallons and compares it with the material volume you plan to add.",
|
|
158
|
+
},
|
|
159
|
+
{ type: "title", text: "Compost Bin Volume Formulas", level: 3 },
|
|
160
|
+
{
|
|
161
|
+
type: "paragraph",
|
|
162
|
+
html: "For a rectangular bin, use <code>width × depth × height</code>. If the measurements are in centimeters, divide the cubic centimeter result by 1,000 to get liters. For a cylindrical bin, use <code>π × radius² × height</code>, where radius is half the inside diameter. Measure the clear space inside the bin and do not count thick walls, legs, or a lid.",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
type: "list",
|
|
166
|
+
items: [
|
|
167
|
+
"<strong>Rectangular:</strong> width × depth × height.",
|
|
168
|
+
"<strong>Cylindrical:</strong> π × radius² × height.",
|
|
169
|
+
"<strong>Liters:</strong> 1,000 cubic centimeters.",
|
|
170
|
+
"<strong>Fill level:</strong> brown volume plus green volume compared with internal capacity.",
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{ type: "title", text: "How Much Browns and Greens to Add", level: 3 },
|
|
174
|
+
{
|
|
175
|
+
type: "paragraph",
|
|
176
|
+
html: "Use two to three parts browns for each part greens by volume as a practical starting point. Browns include dry leaves, shredded cardboard, and small woody material. Greens include food scraps, fresh grass, and other nitrogen rich material. The calculator reports the target brown range, but the pile itself supplies the final feedback through moisture, smell, heat, and airflow.",
|
|
177
|
+
},
|
|
178
|
+
{ type: "title", text: "Read the Moisture and Air Warnings", level: 3 },
|
|
179
|
+
{
|
|
180
|
+
type: "paragraph",
|
|
181
|
+
html: "A pile that feels dry may decompose slowly, while a saturated pile can lose air spaces and develop unpleasant odors. Aim for a wrung out sponge feel. If the pile is wet, add dry bulky browns and turn it. If it is dry, moisten it gradually while turning so the water spreads through the material.",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
type: "tip",
|
|
185
|
+
title: "Use the result as a check, not a prescription",
|
|
186
|
+
html: "The ratio is a volume guideline, not a measured carbon to nitrogen analysis. The calculator does not identify materials, measure temperature, assess contamination, or guarantee finished compost. Keep animal waste, treated wood, and other unsuitable materials out of a home pile according to local guidance.",
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
faq,
|
|
190
|
+
bibliography,
|
|
191
|
+
howTo,
|
|
192
|
+
schemas: [faqSchema, howToSchema, appSchema],
|
|
193
|
+
};
|