init commit
This commit is contained in:
12
.venv/lib/python3.10/site-packages/tailwind/__init__.py
Normal file
12
.venv/lib/python3.10/site-packages/tailwind/__init__.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def get_config(setting_name):
|
||||
return {
|
||||
"NPM_BIN_PATH": getattr(settings, "NPM_BIN_PATH", "npm"),
|
||||
# 'TAILWIND_DEV_MODE' is deprecated. Leaving it here
|
||||
# to support legacy browser-sync based configs.
|
||||
"TAILWIND_DEV_MODE": getattr(settings, "TAILWIND_DEV_MODE", False),
|
||||
"TAILWIND_CSS_PATH": getattr(settings, "TAILWIND_CSS_PATH", "css/dist/styles.css"),
|
||||
"TAILWIND_APP_NAME": getattr(settings, "TAILWIND_APP_NAME", None),
|
||||
}[setting_name]
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"app_name": "",
|
||||
"_copy_without_render": [
|
||||
"templates/base.html"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
APP_NAME_REGEX = r"^[_a-zA-Z][_a-zA-Z0-9]+$"
|
||||
|
||||
app_name = "{{ cookiecutter.app_name }}"
|
||||
|
||||
if not re.match(APP_NAME_REGEX, app_name):
|
||||
print(f"ERROR: {app_name} is not a valid Django app name!")
|
||||
|
||||
# exits with status 1 to indicate failure
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class {{ cookiecutter.app_name[0]|upper }}{{ cookiecutter.app_name[1:] }}Config(AppConfig):
|
||||
name = '{{ cookiecutter.app_name }}'
|
||||
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "{{ cookiecutter.app_name }}",
|
||||
"version": "4.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "npm run dev",
|
||||
"build": "npm run build:clean && npm run build:tailwind",
|
||||
"build:clean": "rimraf ../static/css/dist",
|
||||
"build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify",
|
||||
"dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w",
|
||||
"tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"cross-env": "^7.0.3",
|
||||
"postcss": "^8.5.3",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-nested": "^7.0.2",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"tailwindcss": "^3.4.17"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-import": {},
|
||||
"postcss-simple-vars": {},
|
||||
"postcss-nested": {}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This is a minimal config.
|
||||
*
|
||||
* If you need the full config, get it from here:
|
||||
* https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
content: [
|
||||
/**
|
||||
* HTML. Paths to Django template files that will contain Tailwind CSS classes.
|
||||
*/
|
||||
|
||||
/* Templates within theme app (<tailwind_app_name>/templates), e.g. base.html. */
|
||||
'../templates/**/*.html',
|
||||
|
||||
/*
|
||||
* Main templates directory of the project (BASE_DIR/templates).
|
||||
* Adjust the following line to match your project structure.
|
||||
*/
|
||||
'../../templates/**/*.html',
|
||||
|
||||
/*
|
||||
* Templates in other django apps (BASE_DIR/<any_app_name>/templates).
|
||||
* Adjust the following line to match your project structure.
|
||||
*/
|
||||
'../../**/templates/**/*.html',
|
||||
|
||||
/**
|
||||
* JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure
|
||||
* patterns match your project structure.
|
||||
*/
|
||||
/* JS 1: Ignore any JavaScript in node_modules folder. */
|
||||
// '!../../**/node_modules',
|
||||
/* JS 2: Process all JavaScript files in the project. */
|
||||
// '../../**/*.js',
|
||||
|
||||
/**
|
||||
* Python: If you use Tailwind CSS classes in Python, uncomment the following line
|
||||
* and make sure the pattern below matches your project structure.
|
||||
*/
|
||||
// '../../**/*.py'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
/**
|
||||
* '@tailwindcss/forms' is the forms plugin that provides a minimal styling
|
||||
* for forms. If you don't like it or have own styling for forms,
|
||||
* comment the line below to disable '@tailwindcss/forms'.
|
||||
*/
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/aspect-ratio'),
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{% load static tailwind_tags %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Django Tailwind</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
{% tailwind_css %}
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 font-serif leading-normal tracking-normal">
|
||||
<div class="container mx-auto">
|
||||
<section class="flex items-center justify-center h-screen">
|
||||
<h1 class="text-5xl">Django + Tailwind = ❤️</h1>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"app_name": "",
|
||||
"_copy_without_render": [
|
||||
"templates/base.html"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
APP_NAME_REGEX = r"^[_a-zA-Z][_a-zA-Z0-9]+$"
|
||||
|
||||
app_name = "{{ cookiecutter.app_name }}"
|
||||
|
||||
if not re.match(APP_NAME_REGEX, app_name):
|
||||
print(f"ERROR: {app_name} is not a valid Django app name!")
|
||||
|
||||
# exits with status 1 to indicate failure
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class {{ cookiecutter.app_name[0]|upper }}{{ cookiecutter.app_name[1:] }}Config(AppConfig):
|
||||
name = '{{ cookiecutter.app_name }}'
|
||||
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "{{ cookiecutter.app_name }}",
|
||||
"version": "4.0.1",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start": "npm run dev",
|
||||
"build": "npm run build:clean && npm run build:tailwind",
|
||||
"build:clean": "rimraf ../static/css/dist",
|
||||
"build:tailwind": "cross-env NODE_ENV=production postcss ./src/styles.css -o ../static/css/dist/styles.css --minify",
|
||||
"dev": "cross-env NODE_ENV=development postcss ./src/styles.css -o ../static/css/dist/styles.css --watch"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"postcss": "^8.5.3",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"postcss-nested": "^7.0.2",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"tailwindcss": "^4.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
"postcss-simple-vars": {},
|
||||
"postcss-nested": {}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/**
|
||||
* A catch-all path to Django template files, JavaScript, and Python files
|
||||
* that contain Tailwind CSS classes and will be scanned by Tailwind to generate the final CSS file.
|
||||
*
|
||||
* If your final CSS file is not being updated after code changes, you may want to broaden or narrow
|
||||
* the scope of this path.
|
||||
*/
|
||||
@source "../../../**/*.{html,py,js}";
|
||||
@@ -0,0 +1,19 @@
|
||||
{% load static tailwind_tags %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Django Tailwind</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
{% tailwind_css %}
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 font-serif leading-normal tracking-normal">
|
||||
<div class="container mx-auto">
|
||||
<section class="flex items-center justify-center h-screen">
|
||||
<h1 class="text-5xl">Django + Tailwind = ❤️</h1>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
5
.venv/lib/python3.10/site-packages/tailwind/apps.py
Normal file
5
.venv/lib/python3.10/site-packages/tailwind/apps.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TailwindConfig(AppConfig):
|
||||
name = "tailwind"
|
||||
@@ -0,0 +1,138 @@
|
||||
import os
|
||||
|
||||
from django.core.management.base import CommandError, LabelCommand
|
||||
|
||||
from tailwind import get_config
|
||||
|
||||
from ...npm import NPM, NPMException
|
||||
from ...utils import get_tailwind_src_path, install_pip_package
|
||||
from ...validate import ValidationError, Validations
|
||||
|
||||
|
||||
class Command(LabelCommand):
|
||||
help = "Runs tailwind commands"
|
||||
missing_args_message = """
|
||||
Command argument is missing, please add one of the following:
|
||||
init - to initialize django-tailwind app
|
||||
install - to install npm packages necessary to build tailwind css
|
||||
build - to compile tailwind css into production css
|
||||
start - to start watching css changes for dev
|
||||
check-updates - to list possible updates for tailwind css and its dependencies
|
||||
update - to update tailwind css and its dependencies
|
||||
Usage example:
|
||||
python manage.py tailwind start
|
||||
"""
|
||||
npm = None
|
||||
validate = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Command, self).__init__(*args, **kwargs)
|
||||
self.validate = Validations()
|
||||
|
||||
def add_arguments(self, parser):
|
||||
super(Command, self).add_arguments(parser)
|
||||
parser.add_argument(
|
||||
"--no-input",
|
||||
action="store_true",
|
||||
help="Initializes Tailwind project without user prompts",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tailwind-version",
|
||||
default="4",
|
||||
choices=["3", "4"],
|
||||
help="Specifies the Tailwind version to install",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--app-name",
|
||||
help="Sets default app name on Tailwind project initialization",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-package-lock",
|
||||
action="store_true",
|
||||
help="Disables package-lock.json creation during install",
|
||||
)
|
||||
|
||||
def validate_app(self):
|
||||
try:
|
||||
self.validate.has_settings()
|
||||
app_name = get_config("TAILWIND_APP_NAME")
|
||||
self.validate.is_installed(app_name)
|
||||
self.validate.is_tailwind_app(app_name)
|
||||
except ValidationError as err:
|
||||
raise CommandError(err)
|
||||
|
||||
def handle(self, *labels, **options):
|
||||
return self.handle_labels(*labels, **options)
|
||||
|
||||
def handle_labels(self, *labels, **options):
|
||||
self.validate.acceptable_label(labels[0])
|
||||
if labels[0] != "init":
|
||||
self.validate_app()
|
||||
self.npm = NPM(cwd=get_tailwind_src_path(get_config("TAILWIND_APP_NAME")))
|
||||
|
||||
getattr(self, "handle_" + labels[0].replace("-", "_") + "_command")(*labels[1:], **options)
|
||||
|
||||
def handle_init_command(self, **options):
|
||||
try:
|
||||
from cookiecutter.main import cookiecutter
|
||||
except ImportError:
|
||||
self.stdout.write("Cookiecutter is not found, installing...")
|
||||
try:
|
||||
install_pip_package("cookiecutter")
|
||||
from cookiecutter.main import cookiecutter
|
||||
except ModuleNotFoundError:
|
||||
raise CommandError(
|
||||
"Failed to install 'cookiecutter' via pip. Please install it manually "
|
||||
"(https://pypi.org/project/cookiecutter/) and run 'python manage.py tailwind init' again."
|
||||
)
|
||||
|
||||
try:
|
||||
app_path = cookiecutter(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
|
||||
output_dir=os.getcwd(),
|
||||
directory=f"app_template_v{options['tailwind_version']}",
|
||||
no_input=options["no_input"],
|
||||
overwrite_if_exists=False,
|
||||
extra_context={"app_name": options["app_name"].strip() if options.get("app_name") else "theme"},
|
||||
)
|
||||
|
||||
app_name = os.path.basename(app_path)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f"Tailwind application '{app_name}' "
|
||||
f"has been successfully created. "
|
||||
f"Please add '{app_name}' to INSTALLED_APPS in settings.py, "
|
||||
f"then run the following command to install Tailwind CSS "
|
||||
f"dependencies: `python manage.py tailwind install`"
|
||||
)
|
||||
)
|
||||
except Exception as err:
|
||||
raise CommandError(err)
|
||||
|
||||
def handle_install_command(self, **options):
|
||||
args = ["install"]
|
||||
if options["no_package_lock"]:
|
||||
args.append("--no-package-lock")
|
||||
|
||||
self.npm_command(*args)
|
||||
|
||||
def handle_build_command(self, **options):
|
||||
self.npm_command("run", "build")
|
||||
|
||||
def handle_start_command(self, **options):
|
||||
self.npm_command("run", "start")
|
||||
|
||||
def handle_check_updates_command(self, **options):
|
||||
self.npm_command("outdated")
|
||||
|
||||
def handle_update_command(self, **options):
|
||||
self.npm_command("update")
|
||||
|
||||
def npm_command(self, *args):
|
||||
try:
|
||||
self.npm.command(*args)
|
||||
except NPMException as err:
|
||||
raise CommandError(err)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
37
.venv/lib/python3.10/site-packages/tailwind/npm.py
Normal file
37
.venv/lib/python3.10/site-packages/tailwind/npm.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from tailwind import get_config
|
||||
|
||||
|
||||
class NPMException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NPM:
|
||||
cwd = None
|
||||
npm_bin_path = None
|
||||
|
||||
def __init__(self, cwd=None, npm_bin_path=None):
|
||||
self.npm_bin_path = npm_bin_path if npm_bin_path else get_config("NPM_BIN_PATH")
|
||||
self.cwd = cwd
|
||||
|
||||
def cd(self, cwd):
|
||||
self.cwd = cwd
|
||||
|
||||
def command(self, *args):
|
||||
try:
|
||||
subprocess.run([self.npm_bin_path] + list(args), cwd=self.cwd, check=True)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
sys.exit(1)
|
||||
except OSError:
|
||||
raise NPMException(
|
||||
"\nIt looks like node.js and/or npm is not installed or cannot be found.\n\n"
|
||||
"Visit https://nodejs.org to download and install node.js for your system.\n\n"
|
||||
"If you have npm installed and still getting this error message, "
|
||||
"set NPM_BIN_PATH variable in settings.py to match path of NPM executable in your system.\n\n"
|
||||
""
|
||||
"Example:\n"
|
||||
'NPM_BIN_PATH = "/usr/local/bin/npm"'
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
{% load static %}
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{% if is_static_path %}{% static tailwind_css_path %}{% else %}{{ tailwind_css_path }}{% endif %}{% if v %}?v={{ v }}{% endif %}">
|
||||
|
||||
{# dev_mode is deprecated. Leaving it here to support legacy browser-sync based configs #}
|
||||
{% if dev_mode %}
|
||||
<script id="__bs_script__">//<![CDATA[
|
||||
document.write("<script async src='//HOST:8383/browser-sync/browser-sync-client.js'><\/script>".replace("HOST", location.hostname));
|
||||
//]]></script>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,3 @@
|
||||
{% load static %}
|
||||
|
||||
<link rel="preload" href="{% if is_static_path %}{% static tailwind_css_path %}{% else %}{{ tailwind_css_path }}{% endif %}{% if v %}?v={{ v }}{% endif %}" as="style">
|
||||
@@ -0,0 +1,33 @@
|
||||
import time
|
||||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
|
||||
from tailwind import get_config
|
||||
|
||||
from ..utils import is_path_absolute
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.inclusion_tag("tailwind/tags/css.html")
|
||||
def tailwind_css(v=None):
|
||||
if v is None and settings.DEBUG:
|
||||
# append a time-based suffix to force reload of css in dev mode
|
||||
v = int(time.time())
|
||||
|
||||
return {
|
||||
"dev_mode": get_config("TAILWIND_DEV_MODE"),
|
||||
"v": v,
|
||||
"tailwind_css_path": get_config("TAILWIND_CSS_PATH"),
|
||||
"is_static_path": not is_path_absolute(get_config("TAILWIND_CSS_PATH")),
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag("tailwind/tags/preload_css.html")
|
||||
def tailwind_preload_css(v=None):
|
||||
return {
|
||||
"v": v,
|
||||
"tailwind_css_path": get_config("TAILWIND_CSS_PATH"),
|
||||
"is_static_path": not is_path_absolute(get_config("TAILWIND_CSS_PATH")),
|
||||
}
|
||||
34
.venv/lib/python3.10/site-packages/tailwind/utils.py
Normal file
34
.venv/lib/python3.10/site-packages/tailwind/utils.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
from django.apps import apps
|
||||
|
||||
DJANGO_TAILWIND_APP_DIR = os.path.dirname(__file__)
|
||||
|
||||
|
||||
def get_app_path(app_name):
|
||||
app_label = app_name.split(".")[-1]
|
||||
return apps.get_app_config(app_label).path
|
||||
|
||||
|
||||
def get_tailwind_src_path(app_name):
|
||||
return os.path.join(get_app_path(app_name), "static_src")
|
||||
|
||||
|
||||
def get_package_json_path(app_name):
|
||||
return os.path.join(get_app_path(app_name), "static_src", "package.json")
|
||||
|
||||
|
||||
def get_package_json_contents(app_name):
|
||||
with open(get_package_json_path(app_name), "r") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def is_path_absolute(path):
|
||||
return path.startswith("/") or path.startswith("http")
|
||||
|
||||
|
||||
def install_pip_package(package):
|
||||
import pip._internal as pip
|
||||
|
||||
pip.main(["install", package])
|
||||
36
.venv/lib/python3.10/site-packages/tailwind/validate.py
Normal file
36
.venv/lib/python3.10/site-packages/tailwind/validate.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import os
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
|
||||
from .utils import get_tailwind_src_path
|
||||
|
||||
|
||||
class ValidationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Validations:
|
||||
def acceptable_label(self, label):
|
||||
if label not in [
|
||||
"init",
|
||||
"install",
|
||||
"npm",
|
||||
"start",
|
||||
"build",
|
||||
"check-updates",
|
||||
"update",
|
||||
]:
|
||||
raise ValidationError(f"Subcommand {label} doesn't exist")
|
||||
|
||||
def is_installed(self, app_name):
|
||||
if not apps.is_installed(app_name):
|
||||
raise ValidationError(f"{app_name} is not in INSTALLED_APPS")
|
||||
|
||||
def is_tailwind_app(self, app_name):
|
||||
if not os.path.isfile(os.path.join(get_tailwind_src_path(app_name), "package.json")):
|
||||
raise ValidationError(f"'{app_name}' isn't a Tailwind app")
|
||||
|
||||
def has_settings(self):
|
||||
if not hasattr(settings, "TAILWIND_APP_NAME"):
|
||||
raise ValidationError("TAILWIND_APP_NAME isn't set in settings.py")
|
||||
Reference in New Issue
Block a user