mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-06 07:05:59 +00:00
Setup tailwind with docspell build
This commit is contained in:
parent
b3075cc6dc
commit
442b76c5af
11
build.sbt
11
build.sbt
@ -59,7 +59,7 @@ lazy val noPublish = Seq(
|
|||||||
val elmSettings = Seq(
|
val elmSettings = Seq(
|
||||||
elmCompileMode := ElmCompileMode.Debug,
|
elmCompileMode := ElmCompileMode.Debug,
|
||||||
Compile / resourceGenerators += Def.task {
|
Compile / resourceGenerators += Def.task {
|
||||||
openapiCodegen.value
|
val _ = openapiCodegen.value
|
||||||
compileElm(
|
compileElm(
|
||||||
streams.value.log,
|
streams.value.log,
|
||||||
(Compile / baseDirectory).value,
|
(Compile / baseDirectory).value,
|
||||||
@ -75,6 +75,10 @@ val elmSettings = Seq(
|
|||||||
HiddenFileFilter
|
HiddenFileFilter
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
val stylesSettings = Seq(
|
||||||
|
stylesMode := StylesMode.Dev,
|
||||||
|
Compile / resourceGenerators += stylesBuild.taskValue
|
||||||
|
)
|
||||||
|
|
||||||
val webjarSettings = Seq(
|
val webjarSettings = Seq(
|
||||||
Compile / resourceGenerators += Def.task {
|
Compile / resourceGenerators += Def.task {
|
||||||
@ -406,9 +410,10 @@ val backend = project
|
|||||||
val webapp = project
|
val webapp = project
|
||||||
.in(file("modules/webapp"))
|
.in(file("modules/webapp"))
|
||||||
.disablePlugins(RevolverPlugin)
|
.disablePlugins(RevolverPlugin)
|
||||||
.enablePlugins(OpenApiSchema)
|
.enablePlugins(OpenApiSchema, StylesPlugin)
|
||||||
.settings(sharedSettings)
|
.settings(sharedSettings)
|
||||||
.settings(elmSettings)
|
.settings(elmSettings)
|
||||||
|
.settings(stylesSettings)
|
||||||
.settings(webjarSettings)
|
.settings(webjarSettings)
|
||||||
.settings(
|
.settings(
|
||||||
name := "docspell-webapp",
|
name := "docspell-webapp",
|
||||||
@ -717,7 +722,7 @@ def packageTools(logger: Logger, dir: File, version: String): Seq[File] = {
|
|||||||
|
|
||||||
addCommandAlias(
|
addCommandAlias(
|
||||||
"make",
|
"make",
|
||||||
";set webapp/elmCompileMode := ElmCompileMode.Production ;root/openapiCodegen ;root/test:compile"
|
";set webapp/elmCompileMode := ElmCompileMode.Production; set webapp/stylesMode := StylesMode.Prod ;root/openapiCodegen ;root/test:compile"
|
||||||
)
|
)
|
||||||
addCommandAlias("make-zip", ";restserver/universal:packageBin ;joex/universal:packageBin")
|
addCommandAlias("make-zip", ";restserver/universal:packageBin ;joex/universal:packageBin")
|
||||||
addCommandAlias("make-deb", ";restserver/debian:packageBin ;joex/debian:packageBin")
|
addCommandAlias("make-deb", ";restserver/debian:packageBin ;joex/debian:packageBin")
|
||||||
|
70
modules/webapp/src/main/styles/index.css
Normal file
70
modules/webapp/src/main/styles/index.css
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
@import "@fortawesome/fontawesome-free/css/all";
|
||||||
|
|
||||||
|
/* all @import must be above this line */
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.label {
|
||||||
|
@apply flex flex-row items-center px-2 py-0.5 rounded border ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
@apply py-2 px-4 bg-blue-500 font-semibold rounded-lg shadow-md focus:outline-none focus:ring-2 focus:ring-opacity-75;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.h-screen-10 {
|
||||||
|
height: calc(100vh - 2.5rem);
|
||||||
|
}
|
||||||
|
.h-screen-11 {
|
||||||
|
height: calc(100vh - 2.75rem);
|
||||||
|
}
|
||||||
|
.h-screen-12 {
|
||||||
|
height: calc(100vh - 3rem);
|
||||||
|
}
|
||||||
|
.h-full-10 {
|
||||||
|
height: calc(100% - 2.5rem);
|
||||||
|
}
|
||||||
|
.h-full-11 {
|
||||||
|
height: calc(100% - 2.75rem);
|
||||||
|
}
|
||||||
|
.h-full-12 {
|
||||||
|
height: calc(100% - 3rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-none {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag::before {
|
||||||
|
position: absolute;
|
||||||
|
transform: translateY(-50%) translateX(50%) rotate(-45deg);
|
||||||
|
top: 50%;
|
||||||
|
right: 100%;
|
||||||
|
content: '';
|
||||||
|
background-color: inherit;
|
||||||
|
background-image: none;
|
||||||
|
border-color: inherit;
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
top: 50%;
|
||||||
|
left: -.25em;
|
||||||
|
margin-top: -.25em;
|
||||||
|
background-color: #fff;
|
||||||
|
width: .4em;
|
||||||
|
height: .4em;
|
||||||
|
box-shadow: 0 -1px 1px 0 rgba(0,0,0,.3);
|
||||||
|
border-radius: 500rem;
|
||||||
|
}
|
||||||
|
}
|
2701
package-lock.json
generated
Normal file
2701
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
package.json
Normal file
14
package.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "docspell-css",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||||
|
"autoprefixer": "^10.2.4",
|
||||||
|
"cssnano": "^4.1.10",
|
||||||
|
"postcss": "^8.2.4",
|
||||||
|
"postcss-cli": "^8.3.1",
|
||||||
|
"postcss-import": "^14.0.0",
|
||||||
|
"tailwindcss": "^2.0.2"
|
||||||
|
}
|
||||||
|
}
|
30
postcss.config.js
Normal file
30
postcss.config.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//postcss.config.js
|
||||||
|
const tailwindcss = require("tailwindcss");
|
||||||
|
|
||||||
|
const devPlugins =
|
||||||
|
[
|
||||||
|
require('postcss-import'),
|
||||||
|
tailwindcss("./tailwind.config.js"),
|
||||||
|
require("autoprefixer")
|
||||||
|
];
|
||||||
|
|
||||||
|
const prodPlugins =
|
||||||
|
[
|
||||||
|
require('postcss-import'),
|
||||||
|
tailwindcss("./tailwind.config.js"),
|
||||||
|
require("autoprefixer"),
|
||||||
|
require("@fullhuman/postcss-purgecss")({
|
||||||
|
content: [
|
||||||
|
"./modules/webapp/src/main/elm/**/*.elm",
|
||||||
|
"./modules/restserver/src/main/templates/*.html"
|
||||||
|
],
|
||||||
|
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/\.]+/g) || []
|
||||||
|
}),
|
||||||
|
require('cssnano')({
|
||||||
|
preset: 'default'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = (ctx) => ({
|
||||||
|
plugins: ctx.env === 'production' ? prodPlugins : devPlugins
|
||||||
|
});
|
121
project/StylesPlugin.scala
Normal file
121
project/StylesPlugin.scala
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package docspell.build
|
||||||
|
|
||||||
|
import sbt._
|
||||||
|
import sbt.Keys._
|
||||||
|
import scala.sys.process._
|
||||||
|
|
||||||
|
/** Integrates the tailwind build into sbt.
|
||||||
|
*
|
||||||
|
* It assumes the required config (postcss.conf.js,
|
||||||
|
* tailwind.config.js) files in the base directory. It requires to
|
||||||
|
* have nodejs installed and the npx command available (or
|
||||||
|
* configured).
|
||||||
|
*/
|
||||||
|
object StylesPlugin extends AutoPlugin {
|
||||||
|
|
||||||
|
object autoImport {
|
||||||
|
|
||||||
|
sealed trait StylesMode
|
||||||
|
object StylesMode {
|
||||||
|
case object Prod extends StylesMode
|
||||||
|
case object Dev extends StylesMode
|
||||||
|
}
|
||||||
|
|
||||||
|
val stylesDirectory = settingKey[File]("The directory containing source styles")
|
||||||
|
val stylesOutputDir = settingKey[File]("The directory to put the final outcome")
|
||||||
|
val stylesMode = settingKey[StylesMode]("The compile mode, dev or production")
|
||||||
|
val stylesNpxCommand = settingKey[String]("The npx executable")
|
||||||
|
val stylesNpmCommand =
|
||||||
|
settingKey[String]("The npm executable for installing dependencies")
|
||||||
|
|
||||||
|
val stylesBuild = taskKey[Seq[File]](
|
||||||
|
"Build the css without minifying and purging."
|
||||||
|
)
|
||||||
|
val stylesInstall = taskKey[Unit]("Run npm install to install dependencies")
|
||||||
|
}
|
||||||
|
|
||||||
|
import autoImport._
|
||||||
|
|
||||||
|
def stylesSettings: Seq[Setting[_]] =
|
||||||
|
Seq(
|
||||||
|
stylesDirectory := (Compile / sourceDirectory).value / "styles",
|
||||||
|
stylesOutputDir := (Compile / resourceManaged).value /
|
||||||
|
"META-INF" / "resources" / "webjars" / name.value / version.value,
|
||||||
|
stylesNpxCommand := "npx",
|
||||||
|
stylesNpmCommand := "npm",
|
||||||
|
stylesMode := StylesMode.Dev,
|
||||||
|
stylesBuild := {
|
||||||
|
val logger = streams.value.log
|
||||||
|
val npx = stylesNpxCommand.value
|
||||||
|
val npm = stylesNpmCommand.value
|
||||||
|
val inDir = stylesDirectory.value
|
||||||
|
val outDir = stylesOutputDir.value
|
||||||
|
val wd = (LocalRootProject / baseDirectory).value
|
||||||
|
val mode = stylesMode.value
|
||||||
|
npmInstall(npm, wd, logger)
|
||||||
|
val files = postCss(npx, inDir, outDir, wd, mode, logger) ++
|
||||||
|
copyWebfonts(wd, outDir, logger)
|
||||||
|
logger.info("Styles built")
|
||||||
|
files
|
||||||
|
},
|
||||||
|
stylesInstall := {
|
||||||
|
val logger = streams.value.log
|
||||||
|
val npm = stylesNpmCommand.value
|
||||||
|
val wd = (LocalRootProject / baseDirectory).value
|
||||||
|
npmInstall(npm, wd, logger)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
override def projectSettings: Seq[Setting[_]] =
|
||||||
|
stylesSettings
|
||||||
|
|
||||||
|
def npmInstall(npm: String, wd: File, logger: Logger): Unit = {
|
||||||
|
val modulesDir = wd / "node_modules"
|
||||||
|
if (!modulesDir.exists) {
|
||||||
|
logger.info("Running npm install …")
|
||||||
|
Cmd.run(Seq(npm, "install"), wd, logger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def postCss(
|
||||||
|
npx: String,
|
||||||
|
inDir: File,
|
||||||
|
outDir: File,
|
||||||
|
wd: File,
|
||||||
|
mode: StylesMode,
|
||||||
|
logger: Logger
|
||||||
|
): Seq[File] = {
|
||||||
|
val env = mode match {
|
||||||
|
case StylesMode.Dev => "development"
|
||||||
|
case StylesMode.Prod => "production"
|
||||||
|
}
|
||||||
|
val target = outDir / "css" / "styles.css"
|
||||||
|
IO.createDirectory(target.getParentFile)
|
||||||
|
logger.info("Compiling css stylesheets…")
|
||||||
|
Cmd.run(
|
||||||
|
Seq(
|
||||||
|
npx,
|
||||||
|
"postcss",
|
||||||
|
s"${inDir}/*.css",
|
||||||
|
"-o",
|
||||||
|
target.absolutePath,
|
||||||
|
"--env",
|
||||||
|
env
|
||||||
|
),
|
||||||
|
wd,
|
||||||
|
logger
|
||||||
|
)
|
||||||
|
val gz = file(target.toString + ".gz")
|
||||||
|
IO.gzip(target, gz)
|
||||||
|
Seq(target, gz)
|
||||||
|
}
|
||||||
|
|
||||||
|
def copyWebfonts(baseDir: File, outDir: File, logger: Logger): Seq[File] = {
|
||||||
|
val fontDir =
|
||||||
|
baseDir / "node_modules" / "@fortawesome" / "fontawesome-free" / "webfonts"
|
||||||
|
val targetDir = outDir / "webfonts"
|
||||||
|
IO.createDirectory(targetDir)
|
||||||
|
IO.copy(fontDir.listFiles().map(f => f -> targetDir / f.name).toSeq)
|
||||||
|
IO.listFiles(targetDir).toSeq
|
||||||
|
}
|
||||||
|
}
|
21
tailwind.config.js
Normal file
21
tailwind.config.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// tailwind.config.js
|
||||||
|
|
||||||
|
const colors = require('tailwindcss/colors')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
purge: false,
|
||||||
|
darkMode: 'class', // or 'media' or 'class'
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
bluegray: colors.blueGray,
|
||||||
|
amber: colors.amber,
|
||||||
|
teal: colors.teal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
variants: {},
|
||||||
|
plugins: [
|
||||||
|
]
|
||||||
|
// prefix: 'tw-'
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user