commit 77a53e06a588e0134b0321107add708b9ab8fd68 Author: rhiannon morris Date: Sat Jul 24 03:35:02 2021 +0200 first diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2a6a5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +dist-newstyle +_build +_tmp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b574c1b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lang"] + path = lang + url = https://git.rhiannon.website/rhi/lang diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f6dc4bc --- /dev/null +++ b/Makefile @@ -0,0 +1,112 @@ +HOST ?= rhiannon.website +REMOTE_USER ?= www-data +IDFILE ?= ~/.ssh/xyz +REMOTE_DIR ?= blog + +TMPDIR ?= _tmp +BUILDDIR ?= _build +POSTSDIR ?= posts +TEMPLATEDIR ?= templates + +STATICEXTS := yaml + +POSTS != find $(POSTSDIR) -name '*.md' +STATICS != parallel find $(POSTSDIR) -name '\*.{}' ::: $(STATICEXTS) +OUTPUTPOSTS = \ + $(patsubst $(POSTSDIR)/%.md,$(BUILDDIR)/%.html,$(POSTS)) \ + $(patsubst $(POSTSDIR)/%,$(BUILDDIR)/%,$(STATICS)) \ + $(BUILDDIR)/all-posts.html + +STYLE != find style -type f +OUTPUTSTYLE = $(patsubst %,$(BUILDDIR)/%,$(STYLE)) + +OUTPUT = $(OUTPUTPOSTS) $(OUTPUTSTYLE) + +LANGFILTER = $(TMPDIR)/langfilter +LAANTAS_SCRIPT = $(TMPDIR)/laantas-script +ALL_TAGS = $(TMPDIR)/all-tags +POST_LISTS = $(TMPDIR)/post-lists +NICE_DATE = $(TMPDIR)/nice-date +EXECS = \ + $(LANGFILTER) $(LAANTAS_SCRIPT) \ + $(ALL_TAGS) $(POST_LISTS) $(NICE_DATE) + +CABAL_FLAGS ?= -O -v0 + +.PHONY: all +all: build + +.PHONY: build +build: $(EXECS) $(OUTPUT) + + +POSTDEPS = $(TEMPLATEDIR)/* $(LANGFILTER) $(LAANTAS_SCRIPT) + +$(TMPDIR)/all-tags.md $(TMPDIR)/tags.mk &: $(POSTS) $(ALL_TAGS) + @echo "[all-tags]" + $(ALL_TAGS) $(POSTSDIR) $(TMPDIR)/all-tags.md $(TMPDIR)/tags.mk +build: $(BUILDDIR)/all-tags.html +include $(TMPDIR)/tags.mk + +$(BUILDDIR)/%.html: $(POSTSDIR)/%.md $(POSTDEPS) ; $(call pandoc,post) +$(BUILDDIR)/%.html: $(TMPDIR)/%.md $(POSTDEPS) ; $(call pandoc,meta) + +define pandoc + @echo "[pandoc] $<" + mkdir -p $(dir $@) + mkdir -p $(basename $@) + LAANTAS_SCRIPT="$(LAANTAS_SCRIPT)" \ + DIRNAME="$(basename $@)" \ + FILENAME="$@" \ + pandoc -s --toc --template $(TEMPLATEDIR)/$(1).html -o $@ $< \ + --filter $(LANGFILTER) --filter $(NICE_DATE) --mathjax +endef + + +$(BUILDDIR)/%: $(POSTSDIR)/% ; $(copy) +$(BUILDDIR)/%: $(TMPDIR)/% ; $(copy) +$(BUILDDIR)/%: % ; $(copy) + +define copy + @echo "[copy] $<" + mkdir -p $(dir $@) + cp $< $@ +endef + + +BLOG_META_DEPS != find blog-meta -type f + +$(LANGFILTER): lang/langfilter/* ; $(call cabal-exe) +$(LAANTAS_SCRIPT): lang/laantas-script/* ; $(call cabal-exe) +$(ALL_TAGS): $(BLOG_META_DEPS) ; $(call cabal-exe,blog-meta:) +$(POST_LISTS): $(BLOG_META_DEPS) ; $(call cabal-exe,blog-meta:) +$(NICE_DATE): $(BLOG_META_DEPS) ; $(call cabal-exe,blog-meta:) + +define cabal-exe + @echo "[build] $(notdir $@)" + cabal build $(1)$(notdir $@) $(CABAL_FLAGS) + mkdir -p $(dir $@) + find dist-newstyle -name $(notdir $@) -type f -exec cp {} $(TMPDIR) \; +endef + + +upload: build + @echo "[upload]" + @rsync --recursive --partial --progress --copy-links \ + --compress --human-readable --hard-links --size-only \ + --delete --delete-after \ + --rsh='ssh -l $(REMOTE_USER) -i $(IDFILE)' \ + $(BUILDDIR)/ $(HOST):$(REMOTE_DIR)/ + + + +.PHONY: clean distclean +clean: + @echo "[clean]" + rm -rf $(BUILDDIR) + rm -rf $(TMPDIR) +distclean: clean + @echo "[distclean]" + cabal clean + +.SILENT: diff --git a/blog-meta/all-tags.hs b/blog-meta/all-tags.hs new file mode 100644 index 0000000..7276943 --- /dev/null +++ b/blog-meta/all-tags.hs @@ -0,0 +1,108 @@ +{-# LANGUAGE NamedFieldPuns #-} +module Main (main) where + +import qualified Data.ByteString.Lazy as LazyBS +import Data.Foldable +import Data.Function ((&)) +import qualified Data.Map.Strict as Map +import Data.Set (Set) +import qualified Data.Set as Set +import Data.Text (Text) +import Misc +import qualified System.FilePath.Find as Find +import YAML ((##=), (.!=), (.:)) +import qualified YAML +import System.Environment +import qualified Data.Text.IO as Text +import qualified Data.Text as Text +import Data.Char + + +main :: IO () +main = do + Opts {dir, yaml, make} <- getOptions + files <- Find.findL True (pure True) (Find.extension Find.==? ".md") dir + tags <- traverse getTags files + LazyBS.writeFile yaml $ makeYAML tags + Text.writeFile make $ makeMake tags + +getTags :: FilePath -> IO (Set Text) +getTags file = do + yaml <- YAML.readHeader file + list <- unwrap file $ YAML.parseEither $ + yaml & YAML.withMap "yaml header" \m -> m .: "tags" .!= [] + pure $ Set.fromList list + +makeYAML :: [Set Text] -> LazyBS.ByteString +makeYAML tags = "---\n" <> yaml <> "\n...\n" where + yaml = YAML.encode1 $ YAML.obj + [("title" ##= YAML.str "all tags"), + ("tags" ##= collate tags)] + +makeMake :: [Set Text] -> Text +makeMake tags' = Text.unlines $ build : allPosts : map makeRule tags where + build = Text.unwords $ + "build:" : ["$(BUILDDIR)/" <> t <> ".html" | + t <- ["all-tags", "all-posts"] <> map slug' tags] + makeRule' opt title file = + "$(TMPDIR)/" <> file <> ".md : $(POSTS) $(POST_LISTS)\n\ + \\t@echo \"[post-lists] $<\"\n\ + \\t$(POST_LISTS) " <> opt <> " --out $@ \\\n\ + \\t $(POSTSDIR) \"" <> title <> "\"" + allPosts = makeRule' "" "all posts" "all-posts" + makeRule t = + makeRule' ("--tag \"" <> name t <> "\"") + ("posts tagged ‘" <> name t <> "’") + (slug' t) + slug' (Tag {slug}) = "tag-" <> slug + tags = collate tags' + +data Tag = + Tag { + name :: !Text, + slug :: !Text, + count :: !Int + } + deriving Show + +instance YAML.ToYAML Tag where + toYAML (Tag {name, slug, count}) = YAML.obj $ + [("name" ##= name), ("slug" ##= slug), ("count" ##= count)] + +collate :: [Set Text] -> [Tag] +collate tags₀ = + toList $ fst $ foldl' add1 (mempty, mempty) $ foldMap toList tags₀ + where + add1 (tags, slugs) name + | Map.member name tags = + (Map.adjust incrCount name tags, slugs) + | otherwise = + let tag = makeTag slugs name in + (Map.insert name tag tags, + Set.insert (slug tag) slugs) + makeTag slugs name = + Tag {name, slug = makeSlug slugs name, count = 1} + makeSlug slugs name = head $ filter (`notElem` slugs) candidates where + slug₀ = Text.map toSlugChar name + toSlugChar c + | isAlphaNum c && isAscii c || c == '-' = toLower c + | otherwise = '_' + candidates = slug₀ : [slug₀ <> Text.pack (show i) | i <- [(0 :: Int) ..]] + incrCount t@(Tag {count}) = t {count = succ count} + +data Options = + Opts { + dir :: !FilePath, + yaml :: !FilePath, + make :: !FilePath + } + +getOptions :: IO Options +getOptions = do + args <- getArgs + prog <- getProgName + case args of + [dir, yaml, make] -> pure $ Opts {dir, yaml, make} + _ -> fail $ + "usage: " <> prog <> " DIR YAML MAKE ---\n\ + \ get all tags from posts in DIR and put the results in the given files" diff --git a/blog-meta/blog-meta.cabal b/blog-meta/blog-meta.cabal new file mode 100644 index 0000000..3146d58 --- /dev/null +++ b/blog-meta/blog-meta.cabal @@ -0,0 +1,51 @@ +cabal-version: 2.2 +name: blog-meta +version: 0.1 + +author: rhiannon morris +maintainer: rhiannon morris + +common deps + default-language: Haskell2010 + default-extensions: + BlockArguments, + OverloadedStrings, + OverloadedLists, + NondecreasingIndentation, + ViewPatterns + build-depends: + base ^>= 4.14.2.0, + HsYAML ^>= 0.2.1.0, + bytestring ^>= 0.10.12.0, + containers ^>= 0.6.4.1, + filemanip, + pandoc-types ^>= 1.22, + text ^>= 1.2.4.1, + time ^>= 1.9.3 + ghc-options: -Wall + +common exe + build-depends: blog-meta + ghc-options: -threaded -rtsopts -with-rtsopts=-N + +library + import: deps + hs-source-dirs: lib + exposed-modules: + YAML, + Misc + +executable post-lists + import: deps, exe + hs-source-dirs: . + main-is: post-lists.hs + +executable all-tags + import: deps, exe + hs-source-dirs: . + main-is: all-tags.hs + +executable nice-date + import: deps, exe + hs-source-dirs: . + main-is: nice-date.hs diff --git a/blog-meta/lib/Misc.hs b/blog-meta/lib/Misc.hs new file mode 100644 index 0000000..ed47514 --- /dev/null +++ b/blog-meta/lib/Misc.hs @@ -0,0 +1,22 @@ +module Misc where + +import qualified System.Console.GetOpt as GetOpt +import System.Environment +import System.Exit + +-- | exception on 'Left' +unwrap :: Show a => FilePath -> Either a b -> IO b +unwrap file = either (\x -> fail $ file <> ":" <> show x) return + +getOptionsWith :: (String -> String) -> ([String] -> Maybe a) + -> [GetOpt.OptDescr (a -> a)] -> IO a +getOptionsWith hdr mkDef descrs = do + res <- GetOpt.getOpt GetOpt.Permute descrs <$> getArgs + case res of + (fs, rest, []) | Just def <- mkDef rest -> + return $ foldl (flip ($)) def fs + _ -> do + prog <- getProgName + putStrLn $ GetOpt.usageInfo (hdr prog) descrs + exitFailure + diff --git a/blog-meta/lib/YAML.hs b/blog-meta/lib/YAML.hs new file mode 100644 index 0000000..5f82298 --- /dev/null +++ b/blog-meta/lib/YAML.hs @@ -0,0 +1,52 @@ +module YAML (module YAML) where + +import Data.YAML as YAML +import Data.YAML.Event as YAML (untagged) +import Data.Text (Text) +import qualified Data.Text as Text +import Misc +import Data.ByteString (ByteString) +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as LazyBS +import qualified System.IO as IO + + +str' :: String -> Node () +str' = str . Text.pack + +str :: Text -> Node () +str = Scalar () . SStr + +obj :: Mapping () -> Node () +obj = Mapping () untagged + +(##=) :: (ToYAML b) => Text -> b -> (Node (), Node ()) +(##=) = (#=) + +(#=) :: (ToYAML a, ToYAML b) => a -> b -> (Node (), Node ()) +k #= v = (toYAML k, toYAML v) + +list :: ToYAML a => [a] -> Node () +list = Sequence () untagged . map toYAML + + +-- | read a chunk from the beginning of the file between a +-- @---@ and a @...@. throw an exception if there isn't one +readHeader :: FilePath -> IO (YAML.Node YAML.Pos) +readHeader file = IO.withFile file IO.ReadMode \h -> do + ln <- BS.hGetLine h + if (ln /= "---") then + fail $ file <> ": no header" + else + unwrap file . YAML.decode1 =<< linesUntil "..." h + +-- | read all the lines from a handle until the given terminator. return the +-- lines read, excluding the terminator +linesUntil :: ByteString -> IO.Handle -> IO LazyBS.ByteString +linesUntil end h = go [] where + go acc = do + l <- BS.hGetLine h + if l == end then + return $ LazyBS.fromChunks $ reverse acc + else + go (l <> "\n" : acc) diff --git a/blog-meta/nice-date.hs b/blog-meta/nice-date.hs new file mode 100644 index 0000000..d9e5955 --- /dev/null +++ b/blog-meta/nice-date.hs @@ -0,0 +1,45 @@ +import Text.Pandoc.Definition +import Data.Map.Strict (Map) +import qualified Data.Map.Strict as Map +import Data.Time +import Text.Pandoc.JSON +import Data.Text (Text, unpack, pack) +import Data.Char (toLower) + +main :: IO () +main = toJSONFilter \(Pandoc (Meta m) body) -> do + m' <- niceDate m + pure $ Pandoc (Meta m') body + +niceDate :: Map Text MetaValue -> IO (Map Text MetaValue) +niceDate = Map.alterF reformat "date" + +reformat :: Maybe MetaValue -> IO (Maybe MetaValue) +reformat Nothing = pure Nothing +reformat (Just (toText -> Just txt)) = do + -- extra '-'s in %-m and %-d to allow leading zeroes to be skipped + date <- parseTimeM True defaultTimeLocale "%Y-%-m-%-d" $ unpack txt + let str = formatTime defaultTimeLocale "%A %-e %B %Y" (date :: Day) + pure $ Just $ MetaString $ pack $ map toLower str +reformat (Just d) = fail $ "date is\n" <> show d <> "\nwanted a string" + +toText :: MetaValue -> Maybe Text +toText (MetaString str) = Just str +toText (MetaInlines is) = foldMap inlineText is +toText (MetaBlocks bs) = foldMap blockText bs +toText _ = Nothing + +inlineText :: Inline -> Maybe Text +inlineText (Str txt) = Just txt +inlineText Space = Just " " +inlineText SoftBreak = Just " " +inlineText LineBreak = Just " " +inlineText (RawInline _ txt) = Just txt +inlineText _ = Nothing + +blockText :: Block -> Maybe Text +blockText (Plain is) = foldMap inlineText is +blockText (Para is) = foldMap inlineText is +blockText Null = Just "" +blockText (RawBlock _ txt) = Just txt +blockText _ = Nothing diff --git a/blog-meta/post-lists.hs b/blog-meta/post-lists.hs new file mode 100644 index 0000000..e53f283 --- /dev/null +++ b/blog-meta/post-lists.hs @@ -0,0 +1,100 @@ +import qualified Data.ByteString.Lazy as LazyBS +import Data.Char (toLower) +import Data.Function ((&)) +import Data.List (sortBy) +import Data.Ord (comparing) +import Data.Text (Text) +import qualified Data.Text as Text +import Data.Time +import qualified YAML +import YAML ((.:), (.!=), (##=)) +import qualified System.Console.GetOpt as GetOpt +import qualified System.FilePath.Find as Find +import Misc +import Data.Char (toLower) + +main :: IO () +main = do + Opts title dir tag out <- getOptions + files <- Find.findL True (pure True) (Find.extension Find.==? ".md") dir + infos <- filter (checkTag tag) <$> traverse getInfo files + let content = makeContent title infos + case out of + Nothing -> LazyBS.putStr content + Just fn -> LazyBS.writeFile fn content + +makeContent :: Text -> [PostInfo] -> LazyBS.ByteString +makeContent title is' = "---\n" <> YAML.encode1 val <> "...\n" where + is = sortBy (flip $ comparing infoDate) is' + val = YAML.obj [("title" ##= title), ("posts" ##= is)] + + +checkTag :: Maybe Text -> PostInfo -> Bool +checkTag Nothing _ = True +checkTag (Just t) i = t `elem` infoTags i + + +data Options = + Opts { + optsTitle :: !Text, + optsDir :: !FilePath, + optsTag :: !(Maybe Text), + optsOut :: !(Maybe FilePath) + } + +getOptions :: IO Options +getOptions = getOptionsWith hdr defOpts optDescrs where + hdr prog = "usage: " <> prog <> " [OPTION...] DIR TITLE\n\ + \ --- get info about posts in DIR and use given title" + +optDescrs :: [GetOpt.OptDescr (Options -> Options)] +optDescrs = + [GetOpt.Option "t" ["tag"] + (GetOpt.ReqArg (\t o -> o {optsTag = Just $ Text.pack t}) "TAG") + "list only posts with the given tag", + GetOpt.Option "o" ["out"] + (GetOpt.ReqArg (\f o -> o {optsOut = Just f}) "FILE") + "write output to FILE"] + +defOpts :: [String] -> Maybe Options +defOpts [dir, title] = + Just $ Opts {optsDir = dir, optsTitle = Text.pack title, + optsTag = Nothing, optsOut = Nothing} +defOpts _ = Nothing + + +getInfo :: FilePath -> IO PostInfo +getInfo file = do + yaml <- YAML.readHeader file + unwrap file $ YAML.parseEither $ + yaml & YAML.withMap "title, date, tags" \m -> + Info <$> return (Text.pack file) + <*> m .: "title" + <*> m .: "date" + <*> m .: "tags" .!= [] + +-- | the front matter info we care about +data PostInfo = + Info { + _nfoFile :: Text, + _nfoTitle :: Text, + infoDate :: BlogDate, + infoTags :: [Text] + } + +instance YAML.ToYAML PostInfo where + toYAML (Info file title date tags) = YAML.obj + [("date" ##= date), + ("title" ##= title), + ("tags" ##= tags), + ("file" ##= file)] + +newtype BlogDate = D Day deriving (Eq, Ord) + +instance YAML.FromYAML BlogDate where + parseYAML = YAML.withStr "YYYY-MM-DD" $ + fmap D . parseTimeM True defaultTimeLocale "%F" . Text.unpack + +instance YAML.ToYAML BlogDate where + toYAML (D d) = YAML.str $ Text.pack $ map toLower $ + formatTime defaultTimeLocale "%a %-d %B %Y" d diff --git a/cabal.project b/cabal.project new file mode 100644 index 0000000..c9db746 --- /dev/null +++ b/cabal.project @@ -0,0 +1,8 @@ +packages: + lang/**/*.cabal, + ./blog-meta/blog-meta.cabal + +source-repository-package + type: git + location: https://git.rhiannon.website/rhi/filemanip.git + tag: 0edef8f7bbfe8e210f546e3222b735a32e6055e3 diff --git a/lang b/lang new file mode 160000 index 0000000..3a87859 --- /dev/null +++ b/lang @@ -0,0 +1 @@ +Subproject commit 3a878590c2a15764d5b6e8d4c80bfbc92714f2ae diff --git a/posts/index.md b/posts/index.md new file mode 100644 index 0000000..85c584d --- /dev/null +++ b/posts/index.md @@ -0,0 +1,16 @@ +--- +title: test +tags: [a, b] +date: 2021-07-25 +conlang: laantas +... + +# hello + +im gecs + +:::example +`{#kášńḿł | size=100 ; stroke=4}` +::: + +$$\mathbb{wow},\, \mathcal{MATH}$$ diff --git a/style/counters.css b/style/counters.css new file mode 100644 index 0000000..8dfb591 --- /dev/null +++ b/style/counters.css @@ -0,0 +1,66 @@ +:root { + --section-prefix: ''; +} + +h1::before, h2::before, h3::before, h4::before, h5::before, h6::before { + padding-right: 1ex; +} + +main h1 { + counter-increment: h1; + counter-reset: h2 h3 h4 h5 h6; +} + +main h1::before { + content: var(--section-prefix) counter(h1); +} + +main h2 { + counter-increment: h2; + counter-reset: h3 h4 h5 h6; +} + +main h2::before { + content: var(--section-prefix) counter(h1) '.' counter(h2); +} + +main h3 { + counter-increment: h3; + counter-reset: h4 h5 h6; +} + +main h3::before { + content: var(--section-prefix) counter(h1) '.' counter(h2) '.' counter(h3); +} + +main h4 { + counter-increment: h4; + counter-reset: h5 h6; +} + +main h4::before { + content: var(--section-prefix) + counter(h1) '.' counter(h2) '.' counter(h3) '.' counter(h4); +} + +main h5 { + counter-increment: h5; + counter-reset: h6; +} + +main h5::before { + content: var(--section-prefix) + counter(h1) '.' counter(h2) '.' counter(h3) '.' counter(h4) '.' + counter(h5); +} + +main h6 { + counter-increment: h6; +} + +main h6::before { + content: var(--section-prefix) + counter(h1) '.' counter(h2) '.' counter(h3) '.' counter(h4) '.' + counter(h5) '.' counter(h6); +} + diff --git a/style/page.css b/style/page.css new file mode 100644 index 0000000..de4722f --- /dev/null +++ b/style/page.css @@ -0,0 +1,369 @@ +@import url(fonts/muller/muller.css); +@import url(fonts/junius/junius.css); +@import url(fonts/pragmatapro/pragmatapro.css); + +:root { + --root-col: hsl(30deg, 5%, 26%); + --fg-col: hsl(336deg, 17%, 11%); + --bg-col: hsl(40deg, 91%, 98%); + --link-col: hsl(355deg, 52%, 48%); + + --ipa-font: JuniusX; +} + +:root { + background: var(--root-col); + + font-family: Muller; + font-size: 16pt; + + height: 100vh; +} + +body { + background: url(paper.png), var(--bg-col); + background-blend-mode: multiply; + color: var(--fg-col); + box-shadow: 0 0 5em var(--fg-col); + + max-width: 50em; + min-height: 100%; + margin: 0 auto; + padding: 1em 2em 3em; + + box-sizing: border-box; +} + +header { + text-align: center; +} + +header h1 { + font-size: 350%; + font-weight: 100; + margin-top: 0; +} + +h1, h2, h3, h4, h5, h6 { + margin: 1em 0 0.25em; +} + +h1 { + font-size: 200%; + font-weight: 200; +} + +h2 { + font-size: 180%; + font-weight: 200; +} + +h3 { + font-size: 160%; + font-weight: 200; +} + +h4 { + font-size: 140%; + font-weight: 300; +} + +h5 { + font-size: 120%; + font-weight: 300; +} + +h6 { + font-size: 100%; + font-weight: 400; +} + +header h1 { + margin-bottom: 0.5rem; +} + +hr { + border: 1px solid var(--root-col); + width: 80%; + height: 0; +} + +.meta { + display: flex; + column-gap: 1em; + align-items: baseline; + justify-content: center; +} + +.date { + font-size: 80%; + font-weight: 400; + font-style: italic; + margin-top: 0; +} + +.tags { + font-size: 80%; +} + +.tags ul { + display: inline; + padding: 0; +} + +.tags li { + list-style: none; + display: inline; +} + +.tags li + li { + margin-left: 0.75ex; +} + + +a { + color: var(--link-col); +} + +b, strong { + font-weight: 600; +} + +ul li { + list-style: '— '; +} + +table { + margin: auto; + border-spacing: 0; + border-top: 2px solid var(--root-col); + border-bottom: 2px solid var(--root-col); +} + +th { + font-weight: 500; +} + +thead th { + border-bottom: 1px solid var(--root-col); +} + +td, th { + padding: 0 0.5em; + vertical-align: text-bottom; +} + +code { + font-family: PragmataPro; + font-size: 90%; +} + +pre { + width: min-content; + margin: auto; +} + + +.ipa, .lang, .ebnf-t { + font-family: var(--ipa-font); + + font-feature-settings: + "ccmp", "calt", "liga", "loca", "mark", "mkmk", "ss01"; + /* ss01 to use modern Þþð design, others to make juniusx go brrr + * maybe i can just turn loca off but idk what other regional forms + * it does that i actually want */ + + text-underline-offset: 0.125em; +} + +.ipa { + font-weight: 500; +} + +.lang, .ebnf-t { + font-weight: 700; +} + +.abbr { + font-size: 70%; + font-weight: 500; +} + +.scr { + height: 1.5em; + vertical-align: -40%; + padding-right: 0.5ex; +} + +.gloss .scr { + height: 2em; +} + +:is(.splash, .example) .scr { + height: unset; + display: block; + margin: auto; +} + +.example { + margin: auto; +} + +.example .text { + display: block; + text-align: center; + width: 80%; + margin: 0.75em auto 0; +} + +blockquote { + font-style: italic; +} + + +.letter-list { + margin: 1.25em auto 0; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-around; + width: 80%; + row-gap: 0.5em; + column-gap: 1.5em; +} + +.letter-list + .letter-list { + margin-top: 2.5em; +} + +.letter-list .lang { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.letter-list .scr { + height: 3em; + margin-left: 0.5em; +} + +.letter-list .text { + font-size: 125%; +} + +main nav { + text-align: center; + font-size: 125%; +} + + +#toc > h2 { + font-size: 120%; + font-weight: 300; +} +#toc > ul { + columns: 2; + margin-left: 2em; + margin-right: 2em; +} + +figure:not(.left) { + text-align: center; +} +figure:not(.left) table { + display: inline-table; +} +figure table { + margin: 1em 0.5em; +} +.gloss { + border: none; + text-align: left; +} + +figure ul { + text-align: left; + margin-left: 5em; + margin-right: 5em; + columns: 2; +} +figure li { + break-inside: avoid; +} + +dt { font-weight: 500; float: left; clear: left; } +dd { margin-left: 4em; } + +dt { + break-after: avoid; +} + +dd { + break-before: avoid; +} + +u u { + text-decoration: double underline; +} + +:is(.twocol, .threecol):not(:is(ul, ol) *) { + margin-top: 1em; +} +.twocol { + columns: 2; +} +.threecol { + columns: 3; +} +.twocol :first-child, .threecol :first-child { + margin-top: 0; +} + +footer { + margin: 1.5em auto 1em; + padding-top: 0.5em; + + font-size: 80%; + font-weight: 500; + text-align: center; +} + +.ebnf { + border: none; +} + +.ebnf td { + padding: 0 0.15em; +} + +.ebnf-nt { + font-weight: 500; + color: hsl(155deg, 80%, 30%); + white-space: nowrap; +} + +.ebnf-punc { + color: hsl(25deg, 40%, 30%); +} + +.ebnf-sub, .ebnf-brack { + color: hsl(210deg, 80%, 35%); + font-weight: 500; +} + +.ebnf-brack { + padding: 0 0.05em; +} + +.ebnf-s { + font-style: italic; + color: hsl(330deg, 80%, 30%); +} + +blockquote { + max-width: 70%; + border-left: 1px solid black; + padding-left: 1em; + margin: auto; +} diff --git a/style/paper.png b/style/paper.png new file mode 100644 index 0000000..5977961 Binary files /dev/null and b/style/paper.png differ diff --git a/templates/foot.html b/templates/foot.html new file mode 100644 index 0000000..b893ee7 --- /dev/null +++ b/templates/foot.html @@ -0,0 +1,11 @@ +$if(hide-footer)$$else$ + +$endif$ + +$for(include-after)$ +$include-after$ +$endfor$ diff --git a/templates/head.html b/templates/head.html new file mode 100644 index 0000000..0622dab --- /dev/null +++ b/templates/head.html @@ -0,0 +1,24 @@ + + + + + +$if(show-toc)$ + +$endif$ +$for(css)$ + +$endfor$ + +$for(header-includes)$ +$header-includes$ +$endfor$ +$if(math)$ +$math$ +$endif$ + +$pagetitle$ + +$for(include-before)$ +$include-before$ +$endfor$ diff --git a/templates/meta.html b/templates/meta.html new file mode 100644 index 0000000..4369efe --- /dev/null +++ b/templates/meta.html @@ -0,0 +1,15 @@ +$head()$ + +$if(title)$ +
+

$title$

+
+$endif$ + +$if(posts)$ +$postlist()$ +$elseif(tags)$ +$taglist()$ +$endif$ + +$foot()$ diff --git a/templates/post.html b/templates/post.html new file mode 100644 index 0000000..8a22596 --- /dev/null +++ b/templates/post.html @@ -0,0 +1,46 @@ +$head()$ + +
+ $if(title)$ +

$title$

+ $endif$ +
+ $if(date)$ +

$date$

+ $endif$ + $if(tags)$ + + $endif$ +
+
+
+ + +$if(show-toc)$ + + +$endif$ +
+$body$ + +$if(blah)$ +
+ $for(blah)$ +
$blah.a$ +
$blah.b$ + $endfor$ +
+$endif$ +
+ +$foot()$ diff --git a/templates/postlist.html b/templates/postlist.html new file mode 100644 index 0000000..7aab586 --- /dev/null +++ b/templates/postlist.html @@ -0,0 +1,9 @@ +
+
    + $for(posts)$ +
  • + $it.title$ + ($it.date$) + $endfor$ +
+
diff --git a/templates/taglist.html b/templates/taglist.html new file mode 100644 index 0000000..dd07691 --- /dev/null +++ b/templates/taglist.html @@ -0,0 +1,9 @@ +
+
    + $for(tags)$ +
  • + $it.name$ + ($it.count$) + $endfor$ +
+