Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
orzih committed Jan 30, 2021
0 parents commit 4b4e887
Show file tree
Hide file tree
Showing 14 changed files with 1,185 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# editorconfig.org

root = true

[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,ts,css,scss}]
indent_size = 2

[*.md, *.rst]
trim_trailing_whitespace = false

1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Python Bytecode
*.pyc

# Building and Distributing
/*.egg-info
/.eggs
/build
/dist
/docs/_build

# Various Tools
/.coverage
/coverage.xml
/htmlcov
/env
/venv
/.vagrant
/.cache

# Tests
/.pytest_cache
/tests/test_draw/results
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"cSpell.words": [
"mkdocs",
"orzih"
],
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.enabled": true
}
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contribution Guidelines

Thank you for considering to contribute to this project. These guidelines will help you get going with development and outline the most important rules to follow when submitting pull requests for this project.

## Submitting Changes

To get changes merged, create a pull request. Here are a few things to pay attention to when doing so:

### Commit Messages

The summary of a commit should be concise and worded in an imperative mood.
...a *what* mood? This should clear things up: *[How to Write a Git Commit Message][git-commit-message]*

### Code Style

Make sure your code follows [PEP-8](https://www.python.org/dev/peps/pep-0008/) and keeps things consistent with the rest of the code.

[git-commit-message]: https://chris.beams.io/posts/git-commit/
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# MIT License

Copyright (c) 2021, orzih

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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 OR COPYRIGHT HOLDERS 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.
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
include README.md
include LICENSE.md
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# mkdocs-extra-sass-plugin

[![PyPI version](https://img.shields.io/pypi/v/mkdocs-extra-sass-plugin.svg)](https://pypi.org/project/mkdocs-extra-sass-plugin)
[![PyPI downloads](https://img.shields.io/pypi/dm/mkdocs-extra-sass-plugin.svg)](https://pypi.org/project/mkdocs-extra-sass-plugin)

---

This plugin adds stylesheets to your mkdocs site from `Sass`/`SCSS`.

## Features

* using [LibSass][LibSass] with [libsass-python][libsass-python].

## How to use

### Installation

1. Install the package with pip:

```sh
pip install mkdocs-extra-sass-plugin
```

2. Enable the plugin in your `mkdocs.yml`:

```yml
plugins:
- extra-sass
```

> **Note**: If you have no `plugins` entry in your config file yet, you'll likely also want to add the `search` plugin. MkDocs enables it by default if there is no `plugins` entry set, but now you have to enable it explicitly.
3. Create a `extra_sass` directory in your working directory _(usually the same directory as` mkdocs.yml`)_, and create **entry point file** named `style.css.sass` or `style.css.scss`.

```none
(top)
├── docs
: ...snip...
│   └── index.md
├── extra_sass
: ...snip...
│   └── style.css.scss (or style.css.sass) # compiler entry point file.
└── mkdocs.yml
```

More information about plugins in the [MkDocs documentation][mkdocs-plugins].

## Contributing

From reporting a bug to submitting a pull request: every contribution is appreciated and welcome. Report bugs, ask questions and request features using [Github issues][github-issues].
If you want to contribute to the code of this project, please read the [Contribution Guidelines][contributing].

[LibSass]: https://sass-lang.com/libsass
[libsass-python]: https://github.com/sass/libsass-python
[mkdocs-plugins]: https://www.mkdocs.org/user-guide/plugins/
[github-issues]: https://github.com/orzih/mkdocs-extra-sass-plugin/issues
[contributing]: https://github.com/orzih/mkdocs-extra-sass-plugin/blob/master/CONTRIBUTING.md
1 change: 1 addition & 0 deletions mkdocs_extra_sass_plugin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '0.1.0'
197 changes: 197 additions & 0 deletions mkdocs_extra_sass_plugin/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import io
import logging
import os
from abc import ABC
from tempfile import NamedTemporaryFile
from typing import Type, TypeVar

import sass
from bs4 import BeautifulSoup
from livereload import Server
from mkdocs.config import Config
from mkdocs.plugins import BasePlugin
from mkdocs.structure.pages import Page
from mkdocs.utils import normalize_url

_T_SassEntry = TypeVar('_T', bound='_SassEntry')


_logger = logging.getLogger('mkdocs.extra-sass')


class ExtraSassPlugin(BasePlugin):
"""Extra Sass Plugin"""

def __init__(self):
self.__entry_point = None

def on_config(self, config: Config):
self.__entry_point = None

def on_serve(self, server: Server, config: Config, builder, **kwargs):
self._entry_point(config).on_serve(server, builder)
return server

def on_post_page(
self, output_content: str, page: Page, config: Config
) -> str:
relative_path = self._entry_point(config).relative_path
if not relative_path:
return output_content

# injection

href = normalize_url(relative_path, page=page)

soup = BeautifulSoup(output_content, 'html.parser')

stylesheet = soup.new_tag('link')
stylesheet.attrs['href'] = href
stylesheet.attrs['rel'] = 'stylesheet'

soup.head.append(stylesheet)

_logger.debug(
"[SASS] add on Page: %s, entry_point: %s" %
(page.url, stylesheet))
_logger.debug(str(soup.head))

return str(soup)

# ------------------------------

def _entry_point(self, config: Config) -> _T_SassEntry:
if self.__entry_point is None:
self.__entry_point = self._build_entry(config)
return self.__entry_point

def _build_entry(self, config: Config) -> _T_SassEntry:
entry_point = _SassEntry.search_entry_point()
if entry_point.is_available:
try:
site_dir = config["site_dir"]
dest_dir = os.path.join("assets", "stylesheets")
info = entry_point.save_to(site_dir, dest_dir)
_logger.info(
'[SASS] Build CSS "%s" from "%s"' % (
info['dst'], info['src']))
except Exception as ex:
_logger.exception('[SASS] Failed to build CSS: %s', ex)
if config['strict']:
raise ex

return entry_point


# ==============================
#
#


class _SassEntry(ABC):

_styles_dir = 'extra_sass'
_style_filenames = [
'style.css.sass', 'style.sass',
'style.css.scss', 'style.scss',
]

@classmethod
def search_entry_point(cls: Type[_T_SassEntry]) -> _T_SassEntry:
d = cls._styles_dir
if os.path.isdir(d):
for f in cls._style_filenames:
path = os.path.join(d, f)
if path and os.path.isfile(path):
return _AvailableSassEntry(d, f)
return _NoSassEntry()

@property
def is_available(self) -> bool:
return False

@property
def relative_path(self) -> str:
return ""

def on_serve(self, server: Server, builder) -> None:
pass

def save_to(self, site_dir: str, dest_dir: str) -> dict:
raise AssertionError('DO NOT CALL HERE')


class _NoSassEntry(_SassEntry):
pass


class _AvailableSassEntry(_SassEntry):

def __init__(self, dirname: str, filename: str):
self._dirname = dirname
self._filename = filename

self._relative_path = None

@property
def is_available(self) -> bool:
return True

@property
def relative_path(self) -> str:
""" Compiled CSS file: relative path from `SITE_DIR` """
return self._relative_path

def on_serve(self, server: Server, builder) -> None:
source_path = os.path.join(self._dirname, self._filename)
if os.path.isfile(source_path):
server.watch(self._dirname, builder)

def save_to(self, site_dir: str, dest_dir: str) -> dict:

def fix_umask(temp_file):
# see: https://stackoverflow.com/questions/10541760/can-i-set-the-umask-for-tempfile-namedtemporaryfile-in-python # noqa: E501
umask = os.umask(0o666)
os.umask(umask)
os.chmod(temp_file.name, 0o666 & ~umask)

source_path = os.path.join(self._dirname, self._filename)

output_dir = os.path.join(site_dir, dest_dir)
os.makedirs(output_dir, exist_ok=True)

with NamedTemporaryFile(
prefix='extra-style.',
suffix='.min.css',
dir=output_dir,
delete=False,
mode='w',
encoding='utf-8',
newline=''
) as css_file:
fix_umask(css_file)

_, filename = os.path.split(css_file.name)
source_map_filename = filename + '.map'

css, source_map = sass.compile(
filename=source_path,
output_style='compressed',
source_map_filename=source_map_filename,
source_map_contents=True,
omit_source_map_url=False,
output_filename_hint=filename
)

css_file.write(css)

map_file = os.path.join(output_dir, source_map_filename)
with io.open(map_file, 'w', encoding='utf-8', newline='') as f:
f.write(source_map)

self._relative_path = os.path.join(dest_dir, filename)

return {
'src': source_path,
'dst': self._relative_path
}
Loading

0 comments on commit 4b4e887

Please sign in to comment.