Merge remote-tracking branch 'upstream/master'
commit
b9b5b3ef85
@ -1,12 +0,0 @@
|
||||
<!--
|
||||
- Recipes should be `.md` files in the `src/` directory. Look at already
|
||||
existing `.md` files for examples or see [example](example.md).
|
||||
- File names should be the name of the dish with words separated by hyphens
|
||||
(`-`). Not underscores, and definitely not spaces.
|
||||
- Recipe must be based, i.e. good traditional and substantial food. Nothing
|
||||
ironic, meme-tier hyper-sugary, meat-substitute, etc.
|
||||
- Be sure to add a small number of relevant tags to your recipe (and remove
|
||||
the dummy tags). Try to use already existing tags.
|
||||
- Don't include salt and pepper and other ubiquitous things in the ingredients
|
||||
list.
|
||||
-->
|
@ -1,12 +0,0 @@
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
check_files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check files for compliance
|
||||
run: .github/workflows/scripts/check-files.sh
|
||||
|
@ -1,153 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
SIZE_LIMIT=150000
|
||||
FAIL=0
|
||||
|
||||
check_size() {
|
||||
size="$(stat --printf="%s" "$1")"
|
||||
if [ "$size" -gt "$SIZE_LIMIT" ]; then
|
||||
echo "File $1 is bigger than specified $SIZE_LIMIT limit"
|
||||
FAIL=1
|
||||
fi
|
||||
}
|
||||
|
||||
check_file_name() {
|
||||
fileName="$1"
|
||||
expectedFolder="$2"
|
||||
|
||||
shouldname="${expectedFolder}/$(basename "$fileName" |
|
||||
iconv --to-code=utf-8 |
|
||||
tr '[:upper:]' '[:lower:]' |
|
||||
tr '_ ' '-')"
|
||||
|
||||
if [ "$shouldname" != "$fileName" ]; then
|
||||
echo "$1 should be named $shouldname."
|
||||
FAIL=1
|
||||
fi
|
||||
}
|
||||
|
||||
check_webp_name() {
|
||||
check_file_name "$1" "data/pix"
|
||||
}
|
||||
|
||||
check_recipe_name() {
|
||||
check_file_name "$1" "src"
|
||||
}
|
||||
|
||||
check_recipe_content() {
|
||||
errMsgs="$(awk '
|
||||
BEGIN {
|
||||
HAS_TITLE = 0;
|
||||
HAS_TAGS = 0;
|
||||
HAS_INVALID_TAGS = 0;
|
||||
NUM_TAGS = 0;
|
||||
HAS_INGREDIENTS = 0;
|
||||
HAS_DIRECTIONS = 0;
|
||||
HAS_CONSECUTIVE_EMPTY_LINES = 0;
|
||||
|
||||
CONSECUTIVE_EMPTY_LINES = 0;
|
||||
}
|
||||
|
||||
# First line should be the title
|
||||
NR == 1 && /^# / {
|
||||
HAS_TITLE = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
$0 == "## Ingredients" {
|
||||
HAS_INGREDIENTS = 1;
|
||||
}
|
||||
|
||||
$0 == "## Directions" {
|
||||
HAS_DIRECTIONS = 1;
|
||||
}
|
||||
|
||||
$0 == "" {
|
||||
CONSECUTIVE_EMPTY_LINES++
|
||||
if (CONSECUTIVE_EMPTY_LINES >= 2) {
|
||||
HAS_CONSECUTIVE_EMPTY_LINES = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$0 != "" {
|
||||
CONSECUTIVE_EMPTY_LINES = 0;
|
||||
}
|
||||
|
||||
END {
|
||||
# Last line should be the tags list
|
||||
if ($1 == ";tags:") {
|
||||
HAS_TAGS = 1;
|
||||
NUM_TAGS = NF - 1;
|
||||
|
||||
# Loop through all the tags
|
||||
for (i = 2; i <= NF; i++) {
|
||||
# Make sure that each tag only contains lowercase letters and hyphens
|
||||
if ($i !~ "^[a-z-]+$") {
|
||||
HAS_INVALID_TAGS = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!HAS_TITLE) {
|
||||
print "Recipe does not have a properly formatted title on the first line."
|
||||
}
|
||||
|
||||
if (!HAS_TAGS) {
|
||||
print "Recipe does not have a properly formatted tags on the last line."
|
||||
} else {
|
||||
if (HAS_INVALID_TAGS) {
|
||||
print "Recipe has invalid tags. Tags must be separated by spaces and contain only lowercase letters or hyphens (-)";
|
||||
}
|
||||
|
||||
if (NUM_TAGS < 2) {
|
||||
print "Recipe only has " NUM_TAGS " tags. Add some more."
|
||||
} else if (NUM_TAGS > 5) {
|
||||
print "Recipe has " NUM_TAGS " tags which is too many. Remove some tags."
|
||||
}
|
||||
}
|
||||
|
||||
if (!HAS_INGREDIENTS) {
|
||||
print "Recipe does not have an ingredients list."
|
||||
}
|
||||
|
||||
if (!HAS_DIRECTIONS) {
|
||||
print "Recipe does not have a directions section."
|
||||
}
|
||||
|
||||
if (HAS_CONSECUTIVE_EMPTY_LINES) {
|
||||
print "Recipe has at least 2 consecutive empty lines.";
|
||||
}
|
||||
}
|
||||
' "$1")"
|
||||
|
||||
if [ -n "$errMsgs" ]; then
|
||||
echo "$errMsgs"
|
||||
FAIL=1
|
||||
fi
|
||||
}
|
||||
|
||||
while IFS= read -r file; do
|
||||
echo "Checking '$file'"
|
||||
case "$file" in
|
||||
# Ignore these files
|
||||
index.md) ;;
|
||||
.github/*.md) ;;
|
||||
|
||||
*.webp)
|
||||
check_size "$file"
|
||||
check_webp_name "$file"
|
||||
;;
|
||||
*.md)
|
||||
check_recipe_name "$file"
|
||||
check_recipe_content "$file"
|
||||
;;
|
||||
esac
|
||||
# Separate each file for easier reading.
|
||||
echo ""
|
||||
done <<EOF
|
||||
$(git diff --name-only "$(git merge-base origin/master HEAD)")
|
||||
EOF
|
||||
|
||||
exit $FAIL
|
@ -1,4 +1,10 @@
|
||||
rss.xml
|
||||
atom.xml
|
||||
blog
|
||||
tags
|
||||
/themes/
|
||||
|
||||
# Generated files by hugo
|
||||
/public/
|
||||
/resources/_gen/
|
||||
/assets/jsconfig.json
|
||||
hugo_stats.json
|
||||
|
||||
# Temporary lock file while building
|
||||
/.hugo_build.lock
|
||||
|
@ -1,121 +0,0 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
@ -1,198 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
BLOG := $(MAKE) -f $(lastword $(MAKEFILE_LIST)) --no-print-directory
|
||||
ifneq ($(filter-out help,$(MAKECMDGOALS)),)
|
||||
include config
|
||||
endif
|
||||
|
||||
# The following can be configured in config
|
||||
BLOG_DATE_FORMAT_INDEX ?= %x
|
||||
BLOG_DATE_FORMAT ?= %x %X
|
||||
BLOG_TITLE ?= blog
|
||||
BLOG_DESCRIPTION ?= blog
|
||||
BLOG_URL_ROOT ?= http://localhost/blog
|
||||
BLOG_FEED_MAX ?= 20
|
||||
BLOG_FEEDS ?= rss atom
|
||||
BLOG_SRC ?= articles
|
||||
|
||||
|
||||
.PHONY: help init build deploy clean taglist
|
||||
|
||||
ARTICLES = $(shell git ls-tree HEAD --name-only -- $(BLOG_SRC)/*.md 2>/dev/null)
|
||||
TAGFILES = $(patsubst $(BLOG_SRC)/%.md,tags/%,$(ARTICLES))
|
||||
|
||||
help:
|
||||
$(info make init|build|deploy|clean|taglist)
|
||||
|
||||
init:
|
||||
mkdir -p $(BLOG_SRC) data templates
|
||||
printf '<!DOCTYPE html><html><head><title>$$TITLE</title></head><body>' > templates/header.html
|
||||
printf '</body></html>' > templates/footer.html
|
||||
printf '' > templates/index_header.html
|
||||
printf '<p>Tags:' > templates/tag_list_header.html
|
||||
printf '<a href="$$URL">$$NAME</a>' > templates/tag_entry.html
|
||||
printf ', ' > templates/tag_separator.html
|
||||
printf '</p>' > templates/tag_list_footer.html
|
||||
printf '<h2>Articles</h2><ul id=artlist>' > templates/article_list_header.html
|
||||
printf '<li><a href="$$URL">$$DATE $$TITLE</a></li>' > templates/article_entry.html
|
||||
printf '' > templates/article_separator.html
|
||||
printf '</ul>' > templates/article_list_footer.html
|
||||
printf '' > templates/index_footer.html
|
||||
printf '' > templates/tag_index_header.html
|
||||
printf '' > templates/tag_index_footer.html
|
||||
printf '' > templates/article_header.html
|
||||
printf '' > templates/article_footer.html
|
||||
printf 'blog\n' > .git/info/exclude
|
||||
|
||||
build: blog/index.html tagpages $(patsubst $(BLOG_SRC)/%.md,blog/%.html,$(ARTICLES)) $(patsubst %,blog/%.xml,$(BLOG_FEEDS))
|
||||
|
||||
deploy: build
|
||||
rsync -rLtvz $(BLOG_RSYNC_OPTS) blog/ data/ $(BLOG_REMOTE)
|
||||
|
||||
clean:
|
||||
rm -rf blog tags
|
||||
|
||||
config:
|
||||
printf 'BLOG_REMOTE:=%s\n' \
|
||||
'$(shell printf "Blog remote (eg: host:/var/www/html): ">/dev/tty; head -n1)' \
|
||||
> $@
|
||||
|
||||
tags/%: $(BLOG_SRC)/%.md
|
||||
mkdir -p tags
|
||||
grep -ih '^; *tags:' "$<" | cut -d: -f2- | tr -c '[^a-z\-]' ' ' | sed 's/ */\n/g' | sed '/^$$/d' | sort -u > $@
|
||||
|
||||
blog/index.html: index.md $(ARTICLES) $(TAGFILES) $(addprefix templates/,$(addsuffix .html,header index_header tag_list_header tag_entry tag_separator tag_list_footer article_list_header article_entry article_separator article_list_footer index_footer footer))
|
||||
mkdir -p blog
|
||||
TITLE="$(BLOG_TITLE)"; \
|
||||
PAGE_TITLE="$(BLOG_TITLE)"; \
|
||||
export TITLE; \
|
||||
export PAGE_TITLE; \
|
||||
envsubst < templates/header.html > $@; \
|
||||
envsubst < templates/index_header.html >> $@; \
|
||||
envsubst < templates/tag_list_header.html >> $@; \
|
||||
first=true; \
|
||||
for t in $(shell cat $(TAGFILES) | sort -u); do \
|
||||
"$$first" || envsubst < templates/tag_separator.html; \
|
||||
NAME="$$t" \
|
||||
URL="@$$t.html" \
|
||||
envsubst < templates/tag_entry.html; \
|
||||
first=false; \
|
||||
done >> $@; \
|
||||
envsubst < templates/tag_list_footer.html >> $@; \
|
||||
envsubst < templates/article_list_header.html >> $@; \
|
||||
first=true; \
|
||||
echo $(ARTICLES); \
|
||||
for f in $(ARTICLES); do \
|
||||
printf '%s ' "$$f"; \
|
||||
git log -n 1 --diff-filter=A --date="format:%s $(BLOG_DATE_FORMAT_INDEX)" --pretty=format:'%ad%n' -- "$$f"; \
|
||||
done | sort | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE; do \
|
||||
"$$first" || envsubst < templates/article_separator.html; \
|
||||
URL="`printf '%s' "\$$FILE" | sed 's,^$(BLOG_SRC)/\(.*\).md,\1,'`.html" \
|
||||
DATE="$$DATE" \
|
||||
TITLE="`head -n1 "\$$FILE" | sed -e 's/^# //g'`" \
|
||||
envsubst < templates/article_entry.html; \
|
||||
first=false; \
|
||||
done >> $@; \
|
||||
envsubst < templates/article_list_footer.html >> $@; \
|
||||
markdown < index.md >> $@; \
|
||||
envsubst < templates/index_footer.html >> $@; \
|
||||
envsubst < templates/footer.html >> $@; \
|
||||
|
||||
|
||||
blog/tag/%.html: $(ARTICLES) $(addprefix templates/,$(addsuffix .html,header tag_header index_entry tag_footer footer))
|
||||
|
||||
.PHONY: tagpages
|
||||
tagpages: $(TAGFILES)
|
||||
+$(BLOG) $(patsubst %,blog/@%.html,$(shell cat $(TAGFILES) | sort -u))
|
||||
|
||||
blog/@%.html: $(TAGFILES) $(addprefix templates/,$(addsuffix .html,header tag_index_header tag_list_header tag_entry tag_separator tag_list_footer article_list_header article_entry article_separator article_list_footer tag_index_footer footer))
|
||||
mkdir -p blog
|
||||
PAGE_TITLE="Articles tagged $* -- $(BLOG_TITLE)"; \
|
||||
TAGS="$*"; \
|
||||
TITLE="$(BLOG_TITLE)"; \
|
||||
export PAGE_TITLE; \
|
||||
export TAGS; \
|
||||
export TITLE; \
|
||||
envsubst < templates/header.html > $@; \
|
||||
envsubst < templates/tag_index_header.html >> $@; \
|
||||
envsubst < templates/article_list_header.html >> $@; \
|
||||
first=true; \
|
||||
for f in $(shell awk '$$0 == "$*" { gsub("tags", "$(BLOG_SRC)", FILENAME); print FILENAME ".md"; nextfile; }' $(TAGFILES)); do \
|
||||
printf '%s ' "$$f"; \
|
||||
git log -n 1 --diff-filter=A --date="format:%s $(BLOG_DATE_FORMAT_INDEX)" --pretty=format:'%ad%n' -- "$$f"; \
|
||||
done | sort | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE; do \
|
||||
"$$first" || envsubst < templates/article_separator.html; \
|
||||
URL="`printf '%s' "\$$FILE" | sed 's,^$(BLOG_SRC)/\(.*\).md,\1,'`.html" \
|
||||
DATE="$$DATE" \
|
||||
TITLE="`head -n1 "\$$FILE" | sed -e 's/^# //g'`" \
|
||||
envsubst < templates/article_entry.html; \
|
||||
first=false; \
|
||||
done >> $@; \
|
||||
envsubst < templates/article_list_footer.html >> $@; \
|
||||
envsubst < templates/tag_index_footer.html >> $@; \
|
||||
envsubst < templates/footer.html >> $@; \
|
||||
|
||||
|
||||
blog/%.html: $(BLOG_SRC)/%.md $(addprefix templates/,$(addsuffix .html,header article_header tag_link_header tag_link tag_link_footer article_footer footer))
|
||||
mkdir -p blog
|
||||
TITLE="$(shell head -n1 $< | sed 's/^# \+//')"; \
|
||||
export TITLE; \
|
||||
PAGE_TITLE="$${TITLE} Recipe -- $(BLOG_TITLE)"; \
|
||||
export PAGE_TITLE; \
|
||||
AUTHOR="$(shell git log --format="%an" -- "$<" | tail -n 1)"; \
|
||||
export AUTHOR; \
|
||||
DATE_POSTED="$(shell git log -n 1 --diff-filter=A --date="format:$(BLOG_DATE_FORMAT)" --pretty=format:'%ad' -- "$<")"; \
|
||||
export DATE_POSTED; \
|
||||
DATE_EDITED="$(shell git log -n 1 --date="format:$(BLOG_DATE_FORMAT)" --pretty=format:'%ad' -- "$<")"; \
|
||||
export DATE_EDITED; \
|
||||
TAGS="$(shell grep -i '^; *tags:' "$<" | cut -d: -f2- | paste -sd ',')"; \
|
||||
export TAGS; \
|
||||
envsubst < templates/header.html > $@; \
|
||||
envsubst < templates/article_header.html >> $@; \
|
||||
sed -e '/^;/d' < $< | markdown -f fencedcode >> $@; \
|
||||
envsubst < templates/tag_link_header.html >> $@; \
|
||||
for i in $${TAGS} ; do \
|
||||
TAG_NAME="$$i" \
|
||||
TAG_LINK="./@$$i.html" \
|
||||
envsubst < templates/tag_link.html >> $@; \
|
||||
done; \
|
||||
envsubst < templates/tag_link_footer.html >> $@; \
|
||||
envsubst < templates/article_footer.html >> $@; \
|
||||
envsubst < templates/footer.html >> $@; \
|
||||
|
||||
blog/rss.xml: $(ARTICLES)
|
||||
printf '<?xml version="1.0" encoding="UTF-8"?>\n<rss version="2.0">\n<channel>\n<title>%s</title>\n<link>%s</link>\n<description>%s</description>\n' \
|
||||
"$(BLOG_TITLE)" "$(BLOG_URL_ROOT)" "$(BLOG_DESCRIPTION)" > $@
|
||||
for f in $(ARTICLES); do \
|
||||
printf '%s ' "$$f"; \
|
||||
git log -n 1 --diff-filter=A --date="format:%s %a, %d %b %Y %H:%M:%S %z" --pretty=format:'%ad%n' -- "$$f"; \
|
||||
done | sort -k2nr | head -n $(BLOG_FEED_MAX) | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE; do \
|
||||
printf '<item>\n<title>%s</title>\n<link>%s</link>\n<guid>%s</guid>\n<pubDate>%s</pubDate>\n<description><![CDATA[%s]]></description>\n</item>\n' \
|
||||
"`head -n 1 $$FILE | sed 's/^# //'`" \
|
||||
"$(BLOG_URL_ROOT)`basename $$FILE | sed 's/\.md/\.html/'`" \
|
||||
"$(BLOG_URL_ROOT)`basename $$FILE | sed 's/\.md/\.html/'`" \
|
||||
"$$DATE" \
|
||||
"`markdown < $$FILE`"; \
|
||||
done >> $@
|
||||
printf '</channel>\n</rss>\n' >> $@
|
||||
|
||||
blog/atom.xml: $(ARTICLES)
|
||||
printf '<?xml version="1.0" encoding="UTF-8"?>\n<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">\n<title type="text">%s</title>\n<subtitle type="text">%s</subtitle>\n<updated>%s</updated>\n<link rel="alternate" type="text/html" href="%s"/>\n<id>%s</id>\n<link rel="self" type="application/atom+xml" href="%s"/>\n' \
|
||||
"$(BLOG_TITLE)" "$(BLOG_DESCRIPTION)" "$(shell date +%Y-%m-%dT%H:%M:%SZ)" "$(BLOG_URL_ROOT)" "$(BLOG_URL_ROOT)atom.xml" "$(BLOG_URL_ROOT)/atom.xml" > $@
|
||||
for f in $(ARTICLES); do \
|
||||
printf '%s ' "$$f"; \
|
||||
git log -n 1 --diff-filter=A --date="format:%s %Y-%m-%dT%H:%M:%SZ" --pretty=format:'%ad %aN%n' -- "$$f"; \
|
||||
done | sort -k2nr | head -n $(BLOG_FEED_MAX) | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE AUTHOR; do \
|
||||
printf '<entry>\n<title type="text">%s</title>\n<link rel="alternate" type="text/html" href="%s"/>\n<id>%s</id>\n<published>%s</published>\n<updated>%s</updated>\n<author><name>%s</name></author>\n<summary type="html"><![CDATA[%s]]></summary>\n</entry>\n' \
|
||||
"`head -n 1 $$FILE | sed 's/^# //'`" \
|
||||
"$(BLOG_URL_ROOT)`basename $$FILE | sed 's/\.md/\.html/'`" \
|
||||
"$(BLOG_URL_ROOT)`basename $$FILE | sed 's/\.md/\.html/'`" \
|
||||
"$$DATE" \
|
||||
"`git log -n 1 --date="format:%Y-%m-%dT%H:%M:%SZ" --pretty=format:'%ad' -- "$$FILE"`" \
|
||||
"$$AUTHOR" \
|
||||
"`markdown < $$FILE`"; \
|
||||
done >> $@
|
||||
printf '</feed>\n' >> $@
|
||||
|
||||
taglist:
|
||||
grep -RIh '^;tags:' src | cut -d' ' -f2- | tr ' ' '\n' | sort | uniq
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
---
|
||||
|
@ -1,6 +0,0 @@
|
||||
BLOG_TITLE:=Based Cooking
|
||||
BLOG_REMOTE:=/var/www/based.cooking
|
||||
BLOG_DATE_FORMAT_INDEX:=%F
|
||||
BLOG_DATE_FORMAT:=%F
|
||||
BLOG_SRC:=src
|
||||
BLOG_URL_ROOT:=https://based.cooking/
|
@ -0,0 +1,14 @@
|
||||
baseURL = 'https://based.cooking/'
|
||||
languageCode = 'en-us'
|
||||
title = 'Based Cooking'
|
||||
theme = 'lugo'
|
||||
|
||||
[params]
|
||||
favicon = "/favicon.svg"
|
||||
stylesheet = "/style.css"
|
||||
indexarticles = 50
|
||||
|
||||
[markup]
|
||||
[markup.goldmark]
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true
|
@ -0,0 +1,84 @@
|
||||
---
|
||||
title: "🍲 Based Cooking 🍳"
|
||||
description: 'The fast-loading recipe site with cooking only and no ads.'
|
||||
---
|
||||
|
||||
## What do you want to cook?
|
||||
|
||||
<div class="search js-only">
|
||||
<input type="text" id="search" placeholder="Search ALL Recipes...">
|
||||
<button id="clear-search">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Backspace</title><path d="M135.19 390.14a28.79 28.79 0 0021.68 9.86h246.26A29 29 0 00432 371.13V140.87A29 29 0 00403.13 112H156.87a28.84 28.84 0 00-21.67 9.84v0L46.33 256l88.86 134.11z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// @license magnet:?xt=urn:btih:5ac446d35272cc2e4e85e4325b146d0b7ca8f50c&dn=unlicense.txt Unlicense
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
for (e of document.getElementsByClassName("js-only")) {
|
||||
e.classList.remove("js-only");
|
||||
}
|
||||
|
||||
const recipes = document.querySelectorAll("#artlist li");
|
||||
const search = document.getElementById("search");
|
||||
const oldheading = document.getElementById("newest-recipes");
|
||||
const clearSearch = document.getElementById("clear-search");
|
||||
const artlist = document.getElementById("artlist");
|
||||
|
||||
search.addEventListener("input", () => {
|
||||
// grab search input value
|
||||
const searchText = search.value.toLowerCase().trim().normalize('NFD').replace(/\p{Diacritic}/gu, "");
|
||||
const searchTerms = searchText.split(" ");
|
||||
const hasFilter = searchText.length > 0;
|
||||
|
||||
artlist.classList.toggle("list-searched", hasFilter);
|
||||
oldheading.classList.toggle("hidden", hasFilter);
|
||||
|
||||
// for each recipe hide all but matched
|
||||
recipes.forEach(recipe => {
|
||||
const searchString = `${recipe.textContent} ${recipe.dataset.tags}`.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, "");
|
||||
const isMatch = searchTerms.every(term => searchString.includes(term));
|
||||
|
||||
recipe.hidden = !isMatch;
|
||||
recipe.classList.toggle("matched-recipe", hasFilter && isMatch);
|
||||
})
|
||||
})
|
||||
|
||||
clearSearch.addEventListener("click", () => {
|
||||
search.value = "";
|
||||
recipes.forEach(recipe => {
|
||||
recipe.hidden = false;
|
||||
recipe.classList.remove("matched-recipe");
|
||||
})
|
||||
|
||||
artlist.classList.remove("list-searched");
|
||||
oldheading.classList.remove("hidden");
|
||||
})
|
||||
})
|
||||
// @license-end
|
||||
</script>
|
||||
|
||||
## Newest Recipes
|
||||
|
||||
{{< artlist >}}
|
||||
|
||||
## Or Browse by Category...
|
||||
|
||||
{{< tagcloud >}}
|
||||
|
||||
## About this site
|
||||
|
||||
Founded to provide a simple online cookbook without ads and obese web design.
|
||||
See the story of this site unfold in three videos:
|
||||
|
||||
- [A Demonstration of Modern Web Bloat](https://odysee.com/@Luke:7/a-demonstration-of-modern-web-bloat:f)
|
||||
- [The War Against Web Bloat Continues...](https://odysee.com/@Luke:7/the-war-against-web-bloat-continues...:a)
|
||||
- [SoyDevs DESTROYED Epic Style by Based Cooking!](https://odysee.com/@Luke:7/soydevs-destroyed-epic-style-by-based:6)
|
||||
|
||||
## It's easy to contribute!
|
||||
|
||||
New recipes can be submitted [on Github](https://github.com/lukesmithxyz/based.cooking).
|
||||
We are funded by you only, not 20MB of ads or privacy-violating trackers per page.
|
||||
|
||||
{{< crypto >}}
|
@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "Baby Back Ribs"
|
||||
date: 2022-04-15
|
||||
tags: ['pork', 'american', 'supper', 'southern']
|
||||
author: crazywillbear
|
||||
---
|
||||
|
||||
Some classic and delicious baby back ribs. Keep in mind that if you do not have a smoker, a grill with some tin-foil wrapped smoking wood with poked holes will suffice.
|
||||
|
||||
## Ingredients
|
||||
|
||||
- Applewood (or other sweet cooking wood such as cherry or maple)
|
||||
- 2 baby back rib racks
|
||||
- 1 container of barbecue rub ([Traeger Pork and Poultry Rub](https://www.traeger.com/rubs-spices/pork-poultry) is recommended)
|
||||
- Tin foil
|
||||
- Bag of brown sugar
|
||||
- Bottle of honey
|
||||
- Barbecue Sauce ([Oakland Dust, The One BBQ Sauce](https://www.sincerelysf.com/products/oakland-dust-the-one-bbq-sauce-1) is recommended)
|
||||
- (Optional) A stick of butter
|
||||
|
||||
## Directions
|
||||
|
||||
1. Preheat your smoker to 180 degrees Fahrenheit using applewood.
|
||||
2. Take the membrane off of the back of the ribs if your butcher hasn't already done so ([tutorial](https://www.youtube.com/watch?v=uQVIMKDpZfg))
|
||||
3. Cover both sides of the ribs heavily in your barbecue rub, and let sit at room temp for 30 minutes.
|
||||
4. Place the ribs bone down (meat up) on your smoker, and let smoke at 180 degrees Fahrenheit for 3 hours.
|
||||
5. Take the meat out and place on top of two sheets of tin foil. Then, apply a generous amount of brown sugar and honey to both sides of the ribs, followed by a small amount of the barbecue rub. If you have butter, cut it into slices and add it on the meat side (butter is optional).
|
||||
6. Wrap your ribs in the tin foil and place them back on the smoker at 225 degrees Fahrenheit for 2 hours.
|
||||
7. Take your ribs out of the foil and place them bone down (meat up) on your smoker.
|
||||
8. Apply a generous helping of your barbecue sauce to the ribs once every 30 minutes for an hour (twice).
|
||||
9. Take out of smoker and cover in tin foil, allow to sit for 10-30 minutes before serving.
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
title: "Hamburger dressing"
|
||||
date: 2021-04-06
|
||||
tags: ['sauce', 'basic', 'dressing']
|
||||
author: brox
|
||||
---
|
||||
|
||||
![burger-dressing](/pix/burger-dressing.webp)
|
||||
|
||||
A delicious home made hamburger dressing 🍔
|
||||
|
||||
- ⏲️ Prep time: 1 min
|
||||
- 🍳 Cook time: 1 min
|
||||
|
||||
## Ingredients
|
||||
|
||||
- 3 tbsp [mayonnese or aioli](/mayonnaise-or-aioli)
|
||||
- 2 tbsp ketchup
|
||||
- 1 tbsp sriracha
|
||||
- 1 clove garlic, if using mayonnese and not aioli (optional)
|
||||
|
||||
## Directions
|
||||
|
||||
1. Mix ingredients in a bowl
|
@ -0,0 +1,41 @@
|
||||
---
|
||||
title: 'Butter-based biscuit and cookies'
|
||||
author: 'Arnaud Poittevin'
|
||||
date: 2022-06-29
|
||||
tags: ['snack', 'side', 'dough']
|
||||
---
|
||||
|
||||
This recipe is some basic recommandations for making butter based biscuits (aka shortbread, sablés, cookies ...). The complexity comes from the presence of butter mostly.
|
||||
|
||||
- ⏲️ Prep time: 10 min
|
||||
- ⏲️ Wait time: 1h
|
||||
- 🍳 Cook time: 15 min
|
||||
|
||||
## Ingredients
|
||||
|
||||
- Butter
|
||||
- Flour
|
||||
- White sugar
|
||||
- Eggs (optionnal)
|
||||
|
||||
## Directions
|
||||
|
||||
### Prepare the dough
|
||||
|
||||
1. Mix the sugar and eggs until it gets white
|
||||
2. Add the "Pommade" butter and mix thoroughly until the preparation is airy. "pommade" is french for ointment, this is a specific state of butter that is nor liquid nor solid.
|
||||
3. Gradually add the flour
|
||||
|
||||
### Let it sit
|
||||
|
||||
6. The dough should not be sticky and made into a ball wrapped in cellophane/film
|
||||
7. Put the dough ball 1h in the fridge (15 minutes in the freezer if you are in a hurry **less consistent**). The dough needs to be cold when putting in the oven to prevent butter from flowing out and separating from the dough
|
||||
|
||||
### Cooking the dough
|
||||
|
||||
8. Heat your oven to 200 °C with the cooking tray
|
||||
9. Quickly shape the dough so it remains cold. Most important is the thickness, the thicker it is the longer it has to cook and the more chances the butter flows out.
|
||||
10. Transfer the baking paper with the uncooked shortbreads on the hot cooking tray
|
||||
11. Let cook for 12 to 15 minutes to your liking, the brown colour means the sugar has caramelized and it is crunchy
|
||||
12. Work is not done, when out of the oven, the shortbreads will fill soft and crumbly, they need 1 or 2 minutes of cooling before being solid enough to handle
|
||||
13. Whenever possible transfer the shortbreads on a grid or "oven shelf" so air flow can circulate **Necessary for the texture of the shortbread** otherwise moisture will remain inside and will be less crunchy
|
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: "Ceviche"
|
||||
tags: ['seafood', 'peruvian']
|
||||
author: jacob-smith
|
||||
date: 2022-04-16
|
||||
---
|
||||
|
||||
Ceviche is a South American dish which originated in Peru. The following recipe will only cover
|
||||
the bare minimum ingredients, so feel free to experiment by adding things like garlic, ginger, peppers
|
||||
tomatoes, cilantro, other citrus juices, and anything else you feel might taste good in there.
|
||||
|
||||
- ⏲️ Prep time: 10 min
|
||||
|
||||
## Ingredients
|
||||
|
||||
- Seafood
|
||||
- Red Onion
|
||||
- Lime Juice
|
||||
|
||||
## Directions
|
||||
|
||||
1. Slice your onion as thinly as you can then let them all sit in a
|
||||
bowl of cold water for a while. Soaking your onion slices like this
|
||||
will make it so that their flavor is not as strong so that it won't
|
||||
overpower everything.
|
||||
2. While your onion is soaking cut your chosen seafood into cubes.
|
||||
Ceviche can be made with any type of seafood but fish with white
|
||||
meat native to South America, or things like shrimp and octopus are best. Season your cubed seafood generously with salt
|
||||
and pepper and place in a bowl.
|
||||
3. Squeeze the juice of several limes onto your seafood, remember when
|
||||
shopping for limes the softer ones will have the most juice. You
|
||||
want to get good coverage over all your meat but it is important to
|
||||
remember that there is such a thing as too much lime.
|
||||
4. Add the onion slices then cover and let sit in the fridge. You can
|
||||
get away with eating it after only an hour but ceviche gets better
|
||||
as it ages so it may be best to have more patience and let it sit
|
||||
overnight.
|
@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "Cheese"
|
||||
date: 2022-04-16
|
||||
tags: ['basic', 'cheesefare']
|
||||
author: "SuperDuperDeou"
|
||||
---
|
||||
|
||||
The success of this recipe depends entirely on the quality of the milk. The fresher the milk the better. Your regular UHT milk won't work, because the necessary bacteria have been killed.
|
||||
|
||||
You do not necessary need cow milk, basically every animal milk will work, but the cheese will have vastly different (not necessarily worse) characteristics.
|
||||
|
||||
## Ingredients
|
||||
|
||||
- thermometer
|
||||
- 1 cheesecloth
|
||||
- 1 cheese recipient
|
||||
- 2l of milk
|
||||
- 25g of table salt (optional with aging)
|
||||
- 2g of rennet
|
||||
- Some coarse salt
|
||||
- Oil and vinegar (for aging)
|
||||
|
||||
## Directions
|
||||
|
||||
### Preparation
|
||||
|
||||
Pour the milk and the salt into a pot, stir it well, and heat it up to 35°C.
|
||||
Once the temperature has been reached, add the rennet and stir well.
|
||||
Let it cook until it solidifies (about 1 and a half hours), then cut in 1x1cm squares.
|
||||
Let it rest for half an hour.
|
||||
Pour the cheese into the cheesecloth and il drip until it has completely separated from the liquid part (whey).
|
||||
Place the cheese into the recipient.
|
||||
Cover both sides of the cheese with coarse salt, repeat this operation twice, waiting 1 hour between two saltings.
|
||||
Store in the fridge.
|
||||
|
||||
|
||||
### Aging (optional)
|
||||
|
||||
Store the cheese in a chill place (around 12°C).
|
||||
Every day of aging, flip the cheese upside-down.
|
||||
For the first two weeks, also cover it with oil and vinegar every day.
|
||||
|
||||
|
||||
## Extra: Uses for the whey
|
||||
|
||||
You might have noticed you've obtained way more whey than cheese, it's normal, so you probably want to use it in some way instead of throwing it away.
|
||||
|
||||
If they like acids, you can feed it to your plants: it's pretty much giving them water and fertilizer in one go, you can feed it to your animals, since it's a great source of proteins, it's the prime ingredient of another cheese called "Ricotta", it can be used instead of water in sever recipes, and many other: you can even drink it. People have engineered ways to use the whey since the dawn of cheese.
|
@ -0,0 +1,30 @@
|
||||
---
|
||||
title: "Chicken Tenders Airfried"
|
||||
date: 2021-05-08
|
||||
tags: ['chicken', 'fry']
|
||||
author: mental-outlaw
|
||||
---
|
||||
|
||||
- ⏲️ Prep time: 5 min
|
||||
- 🍳 Cook time: 20 min
|
||||
|
||||
## Ingredients
|
||||
|
||||
- Raw chicken strips
|
||||
- Flour
|
||||
- Egg wash
|
||||
- Bread crumbs
|
||||
- Olive oil
|
||||
- Seasoning: salt and pepper with cayenne or paprika (optional)
|
||||
|
||||
## Directions
|
||||
|
||||
1. In a plate, mix a little over a table spoon of spices into your flour.
|
||||
2. Dip the chicken into the flour one strip at a time coating the entire surface.
|
||||
3. Dip the floured chicken into the eggwash.
|
||||
4. Press the chicken into the breadcrumbs trying to pick up as much as possible.
|
||||
5. Repeat until all strips have been floured egged and breaded.
|
||||
6. Coat both sides of the tenders with a light amount of olive oil.
|
||||
7. Place the tenders into your airfryer, do not layer them on top of each other.
|
||||
8. Set your airfryer to chicken mode and cook for 20 minutes at 360 degrees fahrenheit.
|
||||
9. Serve with honey mustard for maximum effect.
|
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: "Chicken Tikka Masala"
|
||||
tags: ['chicken', 'slowcooked', 'indian']
|
||||
date: 2022-04-16
|
||||
---
|
||||
|
||||
- ⏲️ Prep time: 25 min
|
||||
- 🍳 Cook time: 4 hours
|
||||
- 🍽️ Servings: 8
|
||||
|
||||
## Ingredients
|
||||
|
||||
- 1 can (29 ounces) tomato puree
|
||||
- 1-1/2 cups plain yogurt
|
||||
- 1/2 large onion, finely chopped
|
||||
- 2 tablespoons olive oil
|
||||
- 4-1/2 teaspoons minced fresh gingerroot
|
||||
- 4 garlic cloves, minced
|
||||
- 1 tablespoon [garam masala](/garam-masala)
|
||||
- 2-1/2 teaspoons salt
|
||||
- 1-1/2 teaspoons ground cumin
|
||||
- 1 teaspoon paprika
|
||||
- 3/4 teaspoon pepper
|
||||
- 1/2 teaspoon cayenne pepper
|
||||
- 1/4 teaspoon ground cinnamon
|
||||
- 2-1/2 pounds boneless skinless chicken breasts, cut into 1-1/2-inch cubes
|
||||
- 1 jalapeno pepper, halved and seeded
|
||||
- 1 bay leaf
|
||||
- 1 tablespoon cornstarch
|
||||
- 1 cup heavy whipping cream
|
||||
- Hot cooked basmati rice
|
||||
- Chopped fresh cilantro, optional
|
||||
|
||||
## Directions
|
||||
|
||||
1. In a 5-qt. slow cooker, combine the first 13 ingredients (Can blend these first for convenience). Add chicken, jalapeno and bay leaf. Cook, covered, on low 4 hours or until chicken is tender. Remove jalapeno and bay leaf.
|
||||
2. In a small bowl, mix cornstarch and cream until smooth; gradually stir into sauce. Cook, covered, on high 15-20 minutes or until sauce is thickened. Serve with rice. If desired, sprinkle with cilantro.
|
@ -0,0 +1,26 @@
|
||||
---
|
||||
title: "Cream Cheese"
|
||||
date: 2022-04-16
|
||||
tags: ['basic', 'cheesefare']
|
||||
author: "SuperDuperDeou"
|
||||
---
|
||||
|
||||
## Ingredients
|
||||
|
||||
- thermometer
|
||||
- 1 cheesecloth
|
||||
- 1 cheese recipient
|
||||
- 250ml of fresh, non-UHT milk
|
||||
- 250ml of yogurt
|
||||
- 1lt of fresh cream
|
||||
- 5g of table salt
|
||||
- 6g of of citric acid (contained in 130ml of lemon juice)
|
||||
|
||||
## Directions
|
||||
|
||||
Mix the yogurt, the milk, the cream, the salt, and the sugar into a bowl.
|
||||
Heat the bowl to 80°C while stirring.
|
||||
Once the temperature has been reached, add the citric acid and mix well.
|
||||
Heat up to 90°C, then let it cool down until it reaches room temperature.
|
||||
Pour the cheese into the cheesecloth and let the whey drip.
|
||||
Store in the fridge.
|
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: Croque-monsieur bites
|
||||
tags: ['quick','cheese', 'french']
|
||||
date: 2022-06-24
|
||||
author: "SofianeHamlaoui"
|
||||
---
|
||||
|
||||
![croquemsr](/pix/croque-monsieur.webp)
|
||||
|
||||
- ⏲️ Prep time: 10 min
|
||||
- 🍳 Cook time: 10 min
|
||||
- 🍽️ Servings: 6
|
||||
|
||||
## Ingredients
|
||||
|
||||
- For the bechamel
|
||||
- 50g Butter
|
||||
- 50g Flour
|
||||
- 1 Liter of milk
|
||||
- Salt
|
||||
- Ground Pepper
|
||||
- Nutmeg
|
||||
- For the bites
|
||||
- 12 Slices of bread
|
||||
- 2 Tbsp of Mustard
|
||||
- 12 very thin slices of ham with Italian herbs
|
||||
- 80g grated cheese (Emmental, Comté Gruyère Mimolette
|
||||
|
||||
## Directions
|
||||
|
||||
1. Prepare the béchamel: melt the butter in a heavy-bottomed saucepan.
|
||||
2. As soon as it foams, sprinkle it with flour, salt, pepper, add a pinch of nutmeg, mix.
|
||||
3. Then pour in the milk, little by little (especially not all at once), stirring with a whisk each time, until the sauce thickens.
|
||||
4. Turn on the oven on th. 6/180°, take the baking sheet out of the oven and line it with aluminum foil.
|
||||
5. Spread 6 slices of bread in front of you, spread them with a little mustard, add a layer of béchamel, 1 slice of ham folded in 4, grated cheese, a layer of béchamel, put the other 6 slices of bread on the on top, add a thin layer of béchamel and distribute the rest of the grated cheese.
|
||||
6. Arrange the croque-monsieur on the baking sheet and put them in the oven for about 10 minutes.
|
||||
7. You can place them under the broiler for 3-4 minutes at the end.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue