├── django_kss ├── __init__.py ├── pykss │ ├── contrib │ │ ├── __init__.py │ │ └── django │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── templatetags │ │ │ └── __init__.py │ │ │ ├── views.py │ │ │ ├── templates │ │ │ └── pykss │ │ │ │ └── styleguideblock.html │ │ │ └── static │ │ │ └── pykss │ │ │ └── js │ │ │ └── kss.js │ ├── __init__.py │ ├── exceptions.py │ ├── modifier.py │ ├── parser.py │ ├── section.py │ └── comment.py ├── templatetags │ ├── __init__.py │ ├── kss_extra.py │ └── pykss.py ├── templates │ ├── prototype │ │ └── hello.html │ ├── styleguide-full-content.html │ ├── styleguide-inline-content.html │ ├── styleguide_base.html │ ├── pykss │ │ └── styleguideblock.html │ └── styleguide.html ├── models.py ├── tests.py ├── admin.py ├── static │ ├── css │ │ ├── forms.css │ │ ├── buttons.css │ │ └── layout.css │ └── js │ │ └── kss.js ├── urls.py ├── setup.py ├── utils.py └── views.py ├── django_kss_project ├── sample │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── admin.py │ ├── views.py │ ├── styleguide.py │ └── static │ │ └── css │ │ └── form.css ├── sample2 │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── templates │ │ └── prototype │ │ │ └── ya.html │ ├── models.py │ ├── tests.py │ ├── admin.py │ ├── views.py │ ├── styleguide.py │ └── static │ │ └── cxx │ │ └── form.scss ├── django_kss_project │ ├── __init__.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py ├── static │ └── css │ │ ├── forms.css │ │ └── buttons.css └── manage.py ├── Makefile ├── requirements.txt ├── pictures └── screenshot.png ├── MANIFEST.in ├── .gitignore ├── .idea └── inspectionProfiles │ ├── profiles_settings.xml │ └── Project_Default.xml ├── setup.py └── README.rst /django_kss/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss_project/sample/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss_project/sample2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/django/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/django/models.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss_project/sample/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss_project/django_kss_project/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss_project/sample2/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/django/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_kss/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'tim' 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | upload: 2 | python setup.py sdist bdist upload 3 | -------------------------------------------------------------------------------- /django_kss/templates/prototype/hello.html: -------------------------------------------------------------------------------- 1 |

hellow

2 | -------------------------------------------------------------------------------- /django_kss/pykss/__init__.py: -------------------------------------------------------------------------------- 1 | from .parser import Parser # NOQA 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.7.1 2 | Pygments==2.0.1 3 | wsgiref==0.1.2 4 | -------------------------------------------------------------------------------- /django_kss_project/sample2/templates/prototype/ya.html: -------------------------------------------------------------------------------- 1 |

hellowx

2 | -------------------------------------------------------------------------------- /django_kss/pykss/exceptions.py: -------------------------------------------------------------------------------- 1 | class SectionDoesNotExist(Exception): 2 | pass 3 | -------------------------------------------------------------------------------- /django_kss/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /django_kss/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /django_kss/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dorm7/django_kss/HEAD/pictures/screenshot.png -------------------------------------------------------------------------------- /django_kss_project/sample/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample2/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample2/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample2/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /django_kss_project/sample2/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | recursive-include django_kss/static * 3 | recursive-include django_kss/templates * 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | VENV 3 | venv 4 | dist/ 5 | django_kss.egg-info/ 6 | build/ 7 | django_kss_project/db.sqlite3 8 | *.swp 9 | -------------------------------------------------------------------------------- /django_kss_project/sample/styleguide.py: -------------------------------------------------------------------------------- 1 | styleguide = { 2 | 'source_dir': 'static/css', 3 | 'verbose_name': 'Sample APP', 4 | } -------------------------------------------------------------------------------- /django_kss/templates/styleguide-full-content.html: -------------------------------------------------------------------------------- 1 | {% extends 'styleguide_base.html' %} 2 | 3 | {% block content %} 4 | {% include inline_content %} 5 | {% endblock %} -------------------------------------------------------------------------------- /django_kss_project/sample2/styleguide.py: -------------------------------------------------------------------------------- 1 | styleguide = { 2 | 'source_dir': 'static/cxx', 3 | 'verbose_name': 'Sample APP2', 4 | 'target_files': 'static/cxx/form.scss' 5 | } -------------------------------------------------------------------------------- /django_kss/templates/styleguide-inline-content.html: -------------------------------------------------------------------------------- 1 | {% extends 'styleguide.html' %} 2 | 3 | {% block section %} 4 | Full Page Version 5 | {% include inline_content %} 6 | {% endblock %} -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /django_kss_project/static/css/forms.css: -------------------------------------------------------------------------------- 1 | /* 2 | Form 3 | 4 | Styleguide 2 5 | */ 6 | 7 | /* 8 | Form input. 9 | 10 | .error - When form error. 11 | 12 | Example: 13 | 14 | 15 | Styleguide 2.1 16 | */ 17 | input.error { 18 | border: 1px solid red; 19 | } 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /django_kss_project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | dirname = os.path.dirname(os.path.dirname( os.path.abspath( __file__))) 6 | sys.path.append( 7 | dirname 8 | ) 9 | if __name__ == "__main__": 10 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_kss_project.settings") 11 | from django.core.management import execute_from_command_line 12 | execute_from_command_line(sys.argv) 13 | -------------------------------------------------------------------------------- /django_kss/pykss/modifier.py: -------------------------------------------------------------------------------- 1 | class Modifier(object): 2 | 3 | def __init__(self, name, description): 4 | self.name = name 5 | self.description = description 6 | self.example = '' 7 | 8 | @property 9 | def class_name(self): 10 | return self.name.replace('.', ' ').replace(':', ' pseudo-class-').strip() 11 | 12 | def add_example(self, example): 13 | self.example = example.replace('$modifier_class', '%s' % self.class_name) 14 | -------------------------------------------------------------------------------- /django_kss/static/css/forms.css: -------------------------------------------------------------------------------- 1 | /* 2 | Form input. 3 | 4 | .error - When form error. 5 | 6 | Example: 7 | 8 | 9 | Styleguide 2.1 10 | */ 11 | input.error { 12 | border: 1px solid red; } 13 | 14 | 15 | 16 | /* 17 | Form input. 18 | 19 | .error2 - When form error. 20 | 21 | Example: 22 | 23 | 24 | Styleguide 2.2 25 | */ 26 | input.error2 { 27 | border: 1px solid red; } 28 | -------------------------------------------------------------------------------- /django_kss_project/django_kss_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_kss_project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_kss_project.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /django_kss_project/sample/static/css/form.css: -------------------------------------------------------------------------------- 1 | /* 2 | Form input sample. 3 | 4 | .error - When form error. 5 | 6 | Example: 7 | 8 | 9 | Styleguide 2.1 10 | */ 11 | input.error { 12 | border: 1px solid red; 13 | } 14 | 15 | 16 | 17 | /* 18 | 19 | Form input. 20 | 21 | .error2 - When form error. 22 | 23 | Example: 24 | 25 | 26 | Styleguide 2.2 27 | 28 | */ 29 | input.error2 { 30 | border: 1px solid red; 31 | } 32 | -------------------------------------------------------------------------------- /django_kss_project/sample2/static/cxx/form.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Form input sample. 3 | 4 | .error - When form error. 5 | 6 | Example: 7 | 8 | 9 | Styleguide 1.1 10 | */ 11 | 12 | $color: yellow; 13 | input.error { 14 | border: 1px solid $color; 15 | } 16 | 17 | 18 | 19 | /* 20 | Form input. 21 | 22 | .error2 - When form error. 23 | 24 | Example: 25 | 26 | 27 | Styleguide 1.2 28 | */ 29 | input.error2 { 30 | border: 1px solid $color; 31 | } 32 | 33 | 34 | h1{ 35 | color: green; 36 | } 37 | -------------------------------------------------------------------------------- /django_kss_project/django_kss_project/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from django.conf.urls.static import static 3 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 4 | from django.contrib import admin 5 | 6 | import django_kss.urls 7 | 8 | admin.autodiscover() 9 | 10 | urlpatterns = patterns( 11 | '', 12 | # Examples: 13 | # url(r'^$', 'django_kss_project.views.home', name='home'), 14 | # url(r'^blog/', include('blog.urls')), 15 | 16 | url(r'^admin/', include(admin.site.urls)), 17 | url(r'^', include(django_kss.urls)), 18 | ) 19 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/django/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.views.generic.base import TemplateView 3 | 4 | import pykss 5 | 6 | 7 | class StyleguideMixin(object): 8 | 9 | def get_styleguide(self): 10 | dirs = getattr(settings, 'PYKSS_DIRS', []) 11 | return pykss.Parser(*dirs) 12 | 13 | def get_context_data(self, **kwargs): 14 | context = super(StyleguideMixin, self).get_context_data(**kwargs) 15 | context.update({'styleguide': self.get_styleguide()}) 16 | return context 17 | 18 | 19 | class StyleguideView(StyleguideMixin, TemplateView): 20 | pass 21 | -------------------------------------------------------------------------------- /django_kss/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from .views import AutoStyleGuideView, FullTemplateStyleGuideView, InlineTemplateStyleGuideView 3 | from . import utils 4 | 5 | def make_style_guide_pattern(template_name='styleguide.html'): 6 | view = AutoStyleGuideView.as_view(template_name=template_name) 7 | return patterns( 8 | '', 9 | url(r'^$', view, name='styleguide'), 10 | url(r'^full/(?P.*)/(?P.*\.html)/$', FullTemplateStyleGuideView.as_view(), name='prototype'), 11 | url(r'^(?P.*)/(?P.*\.html)/$', InlineTemplateStyleGuideView.as_view(), name='inline_prototype'), 12 | url(r'^(?P.*)/(?P
.*)/$', view, name='styleguide'), 13 | url(r'^(?P.*)/$', view, name='styleguide'), 14 | ) 15 | 16 | urlpatterns = make_style_guide_pattern() 17 | -------------------------------------------------------------------------------- /django_kss/templatetags/kss_extra.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from pygments import highlight 3 | from pygments.lexers import get_lexer_by_name 4 | from pygments.formatters import HtmlFormatter 5 | 6 | from pygments.util import ClassNotFound 7 | 8 | register = template.Library() 9 | 10 | # Don't use this in the future, just include pykss is okay 11 | 12 | @register.filter(name='highlight_code') 13 | def highlight_code(code, lang): 14 | if code is not None: 15 | try: 16 | lexer = get_lexer_by_name(lang, encoding='utf-8', stripall=True, startinline=True) 17 | except ClassNotFound: 18 | lexer = get_lexer_by_name('text') 19 | formatter = HtmlFormatter(encoding='utf-8', style='colorful', cssclass='highlight', 20 | lineanchors="line") 21 | return highlight(code, lexer, formatter) 22 | else: 23 | return code -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | -------------------------------------------------------------------------------- /django_kss/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup 3 | 4 | BASE_DIR = os.path.dirname(__file__) 5 | 6 | with open(os.path.join(BASE_DIR, 'README.rst')) as readme: 7 | README = readme.read() 8 | 9 | # allow setup.py to be run from any path 10 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 11 | 12 | setup( 13 | name='django-kss', 14 | version='0.1', 15 | packages=['django_kss'], 16 | include_package_data=True, 17 | license='BSD License', # example license 18 | description='A simple Django app to make styleguide', 19 | long_description=README, 20 | install_requires=['pykss'], 21 | url='http://www.example.com/', 22 | author='Tim Hsu', 23 | author_email='tim.yellow@gmail.com', 24 | classifiers=[ 25 | 'Environment :: Web Environment', 26 | 'Framework :: Django', 27 | 'Intended Audience :: Developers', 28 | 'License :: OSI Approved :: BSD License', 29 | 'Operating System :: OS Independent', 30 | 'Programming Language :: Python', 31 | # Replace these appropriately if you are stuck on Python 2. 32 | 'Topic :: Internet :: WWW/HTTP', 33 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 34 | ], 35 | ) 36 | -------------------------------------------------------------------------------- /django_kss/pykss/parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from .comment import CommentParser 4 | from .exceptions import SectionDoesNotExist 5 | from .section import Section 6 | 7 | 8 | class Parser(object): 9 | 10 | def __init__(self, *paths): 11 | self.paths = paths 12 | 13 | def parse(self): 14 | sections = {} 15 | 16 | filenames = [os.path.join(subpath, filename) 17 | for path in self.paths 18 | for subpath, dirs, files in os.walk(path) 19 | for filename in files] 20 | 21 | for filename in filenames: 22 | parser = CommentParser(filename) 23 | for block in parser.blocks: 24 | section = Section(block, os.path.basename(filename)) 25 | if section.section: 26 | sections[section.section] = section 27 | 28 | return sections 29 | 30 | @property 31 | def sections(self): 32 | if not hasattr(self, '_sections'): 33 | self._sections = self.parse() 34 | return self._sections 35 | 36 | def section(self, reference): 37 | try: 38 | return self.sections[reference] 39 | except KeyError: 40 | raise SectionDoesNotExist('Section "%s" does not exist.' % reference) 41 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | 4 | with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme: 5 | README = readme.read() 6 | 7 | # allow setup.py to be run from any path 8 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 9 | 10 | setup( 11 | name='django-kss-styleguide', 12 | version='0.5.8', 13 | packages=find_packages() , 14 | include_package_data=True, 15 | license='BSD License', # example license 16 | description='A simple Django app to make styleguide', 17 | long_description=README, 18 | url='https://github.com/timtan/django_kss', 19 | author='Tim Hsu', 20 | author_email='tim.yellow@gmail.com', 21 | install_requires = ['Pygments', 'django_compressor', 'django-libsass'], 22 | classifiers=[ 23 | 'Environment :: Web Environment', 24 | 'Framework :: Django', 25 | 'Intended Audience :: Developers', 26 | 'License :: OSI Approved :: BSD License', 27 | 'Operating System :: OS Independent', 28 | 'Programming Language :: Python', 29 | # Replace these appropriately if you are stuck on Python 2. 30 | 'Topic :: Internet :: WWW/HTTP', 31 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/django/templates/pykss/styleguideblock.html: -------------------------------------------------------------------------------- 1 |
2 | {% block styleguide_header %} 3 |

{{ section.section }} {{ section.filename }}

4 | {% endblock %} 5 | 6 | {% block styleguide_description %} 7 |
8 |

{{ section.description }}

9 | {% if section.modifiers %} 10 |
    11 | {% for modifier in section.modifiers %} 12 |
  • {{ modifier.name }} - {{ modifier.description }}
  • 13 | {% endfor %} 14 |
15 | {% endif %} 16 |
17 | {% endblock %} 18 | 19 | {% block styleguide_element %} 20 |
21 | {{ section.example|safe }} 22 |
23 | {% endblock %} 24 | 25 | {% block styleguide_modifier_elements %} 26 | {% for modifier in section.modifiers %} 27 |
28 | {{ modifier.name }} 29 | {{ modifier.example|safe }} 30 |
31 | {% endfor %} 32 | {% endblock %} 33 | 34 | {% block styleguide_code %} 35 |
{{ section.example|escape }}
36 | {% endblock %} 37 |
38 | -------------------------------------------------------------------------------- /django_kss/templates/styleguide_base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% load static %} 5 | {% load pykss %} 6 | {% load compress %} 7 | 8 | 9 | 10 | 11 | 12 | Styleguide Example 13 | 14 | 15 | {% for user_css_file, is_scss in css_source_files %} 16 | {% if is_scss%} 17 | {% compress css %} 18 | 19 | {% endcompress %} 20 | {% else %} 21 | 22 | {% endif %} 23 | {% endfor %} 24 | 25 | {% block style %} {% endblock %} 26 | 29 | 30 | 31 | 32 | 33 | {% block content %} {% endblock %} 34 | {% block buttom %} {% endblock %} 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /django_kss/templates/pykss/styleguideblock.html: -------------------------------------------------------------------------------- 1 | {% load kss_extra %} 2 | 3 |
4 | {% block styleguide_header %} 5 |

{{ section.section }} {{ section.filename }}

6 | {% endblock %} 7 | 8 | {% block styleguide_description %} 9 |
10 |

{{ section.description }}

11 | {% if section.modifiers %} 12 |
    13 | {% for modifier in section.modifiers %} 14 |
  • {{ modifier.name }} - {{ modifier.description }}
  • 15 | {% endfor %} 16 |
17 | {% endif %} 18 |
19 | {% endblock %} 20 | 21 | {% block styleguide_element %} 22 |
23 | {{ section.example|safe }} 24 |
25 | {% endblock %} 26 | 27 | {% block styleguide_modifier_elements %} 28 | {% for modifier in section.modifiers %} 29 |
30 | {{ modifier.name }} 31 | {{ modifier.example|safe }} 32 |
33 | {% endfor %} 34 | {% endblock %} 35 | 36 | 37 | {% block styleguide_code %} 38 | {%if section.example %} 39 |
40 | {{ section.example| highlight_code:'html' | safe}} 41 |
42 | {%endif%} 43 | {% endblock %} 44 | 45 | 46 |
47 | -------------------------------------------------------------------------------- /django_kss/templates/styleguide.html: -------------------------------------------------------------------------------- 1 | {% extends 'styleguide_base.html' %} 2 | {% load static %} 3 | {% load pykss %} 4 | {% load compress %} 5 | 6 | {% block content %} 7 | 8 |
9 |
10 |
11 | {% block header %} Django Style Guide {% endblock %} 12 |
13 |
    14 | {% for name, setting in styleguide_settings %} 15 |
  • {{ setting.verbose_name}}
  • 16 | {% endfor %} 17 |
18 |
19 |
20 | 21 | 22 |
23 | 24 | 25 |
    26 | {% for file_name in file_names %} 27 |
  • 28 | 29 | {{ file_name }} 30 | 31 |
  • 32 | {% endfor %} 33 | {% for html in htmls %} 34 |
  • 35 | 36 | {{ html }} 37 | 38 |
  • 39 | {% endfor %} 40 |
41 | 42 | 43 | {% block section %} 44 | {% renderstyleguide styleguide current_section %} 45 | {% endblock %} 46 | 47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | {% endblock %} 56 | -------------------------------------------------------------------------------- /django_kss/pykss/contrib/django/static/pykss/js/kss.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var KssStateGenerator; 3 | 4 | KssStateGenerator = (function() { 5 | var pseudo_selectors; 6 | 7 | pseudo_selectors = ['hover', 'enabled', 'disabled', 'active', 'visited', 'focus', 'target', 'checked', 'empty', 'first-of-type', 'last-of-type', 'first-child', 'last-child']; 8 | 9 | function KssStateGenerator() { 10 | var idx, idxs, pseudos, replaceRule, rule, stylesheet, _i, _len, _len2, _ref, _ref2; 11 | pseudos = new RegExp("(\\:" + (pseudo_selectors.join('|\\:')) + ")", "g"); 12 | try { 13 | _ref = document.styleSheets; 14 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 15 | stylesheet = _ref[_i]; 16 | if (stylesheet.href && stylesheet.href.indexOf(document.domain) >= 0) { 17 | idxs = []; 18 | _ref2 = stylesheet.cssRules; 19 | for (idx = 0, _len2 = _ref2.length; idx < _len2; idx++) { 20 | rule = _ref2[idx]; 21 | if ((rule.type === CSSRule.STYLE_RULE) && pseudos.test(rule.selectorText)) { 22 | replaceRule = function(matched, stuff) { 23 | return matched.replace(/\:/g, '.pseudo-class-'); 24 | }; 25 | this.insertRule(rule.cssText.replace(pseudos, replaceRule)); 26 | } 27 | pseudos.lastIndex = 0; 28 | } 29 | } 30 | } 31 | } catch (_error) {} 32 | } 33 | 34 | KssStateGenerator.prototype.insertRule = function(rule) { 35 | var headEl, styleEl; 36 | headEl = document.getElementsByTagName('head')[0]; 37 | styleEl = document.createElement('style'); 38 | styleEl.type = 'text/css'; 39 | if (styleEl.styleSheet) { 40 | styleEl.styleSheet.cssText = rule; 41 | } else { 42 | styleEl.appendChild(document.createTextNode(rule)); 43 | } 44 | return headEl.appendChild(styleEl); 45 | }; 46 | 47 | return KssStateGenerator; 48 | 49 | })(); 50 | 51 | new KssStateGenerator; 52 | 53 | }).call(this); -------------------------------------------------------------------------------- /django_kss/static/js/kss.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by tim on 14/12/23. 3 | */ 4 | (function() { 5 | var KssStateGenerator; 6 | 7 | KssStateGenerator = (function() { 8 | var pseudo_selectors; 9 | 10 | pseudo_selectors = ['hover', 'enabled', 'disabled', 'active', 'visited', 'focus', 'target', 'checked', 'empty', 'first-of-type', 'last-of-type', 'first-child', 'last-child']; 11 | 12 | function KssStateGenerator() { 13 | var idx, idxs, pseudos, replaceRule, rule, stylesheet, _i, _len, _len2, _ref, _ref2; 14 | pseudos = new RegExp("(\\:" + (pseudo_selectors.join('|\\:')) + ")", "g"); 15 | try { 16 | _ref = document.styleSheets; 17 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 18 | stylesheet = _ref[_i]; 19 | if (stylesheet.href && stylesheet.href.indexOf(document.domain) >= 0) { 20 | idxs = []; 21 | _ref2 = stylesheet.cssRules; 22 | for (idx = 0, _len2 = _ref2.length; idx < _len2; idx++) { 23 | rule = _ref2[idx]; 24 | if ((rule.type === CSSRule.STYLE_RULE) && pseudos.test(rule.selectorText)) { 25 | replaceRule = function(matched, stuff) { 26 | return matched.replace(/\:/g, '.pseudo-class-'); 27 | }; 28 | this.insertRule(rule.cssText.replace(pseudos, replaceRule)); 29 | } 30 | pseudos.lastIndex = 0; 31 | } 32 | } 33 | } 34 | } catch (_error) {} 35 | } 36 | 37 | KssStateGenerator.prototype.insertRule = function(rule) { 38 | var headEl, styleEl; 39 | headEl = document.getElementsByTagName('head')[0]; 40 | styleEl = document.createElement('style'); 41 | styleEl.type = 'text/css'; 42 | if (styleEl.styleSheet) { 43 | styleEl.styleSheet.cssText = rule; 44 | } else { 45 | styleEl.appendChild(document.createTextNode(rule)); 46 | } 47 | return headEl.appendChild(styleEl); 48 | }; 49 | 50 | return KssStateGenerator; 51 | 52 | })(); 53 | 54 | new KssStateGenerator; 55 | 56 | }).call(this); -------------------------------------------------------------------------------- /django_kss/static/css/buttons.css: -------------------------------------------------------------------------------- 1 | /* 2 | Buttons 3 | 4 | Styleguide 1 5 | */ 6 | 7 | /* 8 | Your standard form button. 9 | 10 | :hover - Highlights when hovering. 11 | :disabled - Dims the button when disabled. 12 | .primary - Indicates button is the primary action. 13 | .smaller - A smaller button 14 | 15 | Styleguide 1.1 16 | */ 17 | button { 18 | padding: 5px 15px; 19 | line-height: normal; 20 | font-family: "Helvetica Neue", Helvetica; 21 | font-size: 12px; 22 | font-weight: bold; 23 | color: #666; 24 | text-shadow: 0 1px rgba(255, 255, 255, 0.9); 25 | border-radius: 3px; 26 | border: 1px solid #ddd; 27 | border-bottom-color: #bbb; 28 | background: #f5f5f5; 29 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='$start', endColorstr='$end'); 30 | background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e5e5e5)); 31 | background: -moz-linear-gradient(top, #f5f5f5, #e5e5e5); 32 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); 33 | cursor: pointer; } 34 | button.primary, button.primary:hover { 35 | color: #fff; 36 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.4); 37 | border-color: #74bb5a; 38 | border-bottom-color: #509338; 39 | background: #8add6d; 40 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='$start', endColorstr='$end'); 41 | background: -webkit-gradient(linear, left top, left bottom, from(#8add6d), to(#60b044)); 42 | background: -moz-linear-gradient(top, #8add6d, #60b044); 43 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); } 44 | button.smaller { 45 | font-size: 11px; 46 | padding: 4px 7px; } 47 | button:hover { 48 | color: #337797; 49 | background: #f0f7fa; 50 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='$start', endColorstr='$end'); 51 | background: -webkit-gradient(linear, left top, left bottom, from(#f0f7fa), to(#d8eaf2)); 52 | background: -moz-linear-gradient(top, #f0f7fa, #d8eaf2); 53 | border-color: #cbe3ee; 54 | border-bottom-color: #97c7dd; } 55 | button:disabled { 56 | opacity: 0.5; } 57 | -------------------------------------------------------------------------------- /django_kss_project/static/css/buttons.css: -------------------------------------------------------------------------------- 1 | /* 2 | Buttons 3 | 4 | Styleguide 1 5 | */ 6 | 7 | 8 | /* 9 | Your standard form button. 10 | 11 | :hover - Highlights when hovering. 12 | :disabled - Dims the button when disabled. 13 | .primary - Indicates button is the primary action. 14 | .smaller - A smaller button 15 | 16 | Example: 17 | 18 | 19 | Styleguide 1.1 20 | */ 21 | button { 22 | padding: 5px 15px; 23 | line-height: normal; 24 | font-family: "Helvetica Neue", Helvetica; 25 | font-size: 12px; 26 | font-weight: bold; 27 | color: #666; 28 | text-shadow: 0 1px rgba(255, 255, 255, 0.9); 29 | border-radius: 3px; 30 | border: 1px solid #ddd; 31 | border-bottom-color: #bbb; 32 | background: #f5f5f5; 33 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='$start', endColorstr='$end'); 34 | background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e5e5e5)); 35 | background: -moz-linear-gradient(top, #f5f5f5, #e5e5e5); 36 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); 37 | cursor: pointer; } 38 | button.primary, button.primary:hover { 39 | color: #fff; 40 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.4); 41 | border-color: #74bb5a; 42 | border-bottom-color: #509338; 43 | background: #8add6d; 44 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='$start', endColorstr='$end'); 45 | background: -webkit-gradient(linear, left top, left bottom, from(#8add6d), to(#60b044)); 46 | background: -moz-linear-gradient(top, #8add6d, #60b044); 47 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); } 48 | button.smaller { 49 | font-size: 11px; 50 | padding: 4px 7px; } 51 | button:hover { 52 | color: #337797; 53 | background: #f0f7fa; 54 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='$start', endColorstr='$end'); 55 | background: -webkit-gradient(linear, left top, left bottom, from(#f0f7fa), to(#d8eaf2)); 56 | background: -moz-linear-gradient(top, #f0f7fa, #d8eaf2); 57 | border-color: #cbe3ee; 58 | border-bottom-color: #97c7dd; } 59 | button:disabled { 60 | opacity: 0.5; } 61 | -------------------------------------------------------------------------------- /django_kss/pykss/section.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from .modifier import Modifier 4 | 5 | 6 | CLASS_MODIFIER = '.' 7 | PSEUDO_CLASS_MODIFIER = ':' 8 | MODIFIER_DESCRIPTION_SEPARATOR = ' - ' 9 | EXAMPLE_START = 'Example:' 10 | REFERENCE_START = 'Styleguide' 11 | 12 | reference_re = re.compile(r'%s ([\d\.]+)' % REFERENCE_START) 13 | optional_re = re.compile(r'\[(.*)\]\?') 14 | 15 | 16 | class Section(object): 17 | 18 | def __init__(self, comment=None, filename=None): 19 | self.comment = comment or '' 20 | self.filename = filename 21 | 22 | def parse(self): 23 | self._description_lines = [] 24 | self._modifiers = [] 25 | self._example_lines = [] 26 | self._reference = None 27 | 28 | in_example = False 29 | 30 | for line in self.comment.splitlines(): 31 | if line.startswith(CLASS_MODIFIER) or line.startswith(PSEUDO_CLASS_MODIFIER): 32 | try: 33 | modifier, description = line.split(MODIFIER_DESCRIPTION_SEPARATOR) 34 | except ValueError: 35 | pass 36 | else: 37 | self._modifiers.append(Modifier(modifier.strip(), description.strip())) 38 | 39 | elif line.startswith(EXAMPLE_START): 40 | in_example = True 41 | 42 | elif line.startswith(REFERENCE_START): 43 | in_example = False 44 | self._reference = reference_re.match(line).groups()[0].rstrip('.') 45 | 46 | elif in_example is True: 47 | self._example_lines.append(line) 48 | 49 | else: 50 | self._description_lines.append(line) 51 | 52 | self._description = '\n'.join(self._description_lines).strip() 53 | self.add_example('\n'.join(self._example_lines).strip()) 54 | 55 | @property 56 | def description(self): 57 | if not hasattr(self, '_description'): 58 | self.parse() 59 | return self._description 60 | 61 | @property 62 | def modifiers(self): 63 | if not hasattr(self, '_modifiers'): 64 | self.parse() 65 | return self._modifiers 66 | 67 | @property 68 | def example(self): 69 | if not hasattr(self, '_modifiers'): 70 | self.parse() 71 | return self._example 72 | 73 | @property 74 | def section(self): 75 | if not hasattr(self, '_reference'): 76 | self.parse() 77 | return self._reference 78 | 79 | def add_example(self, example): 80 | self._example = optional_re.sub('', example).replace('$modifier_class', '') 81 | for modifier in self._modifiers: 82 | modifier.add_example(optional_re.sub(r'\1', example)) 83 | -------------------------------------------------------------------------------- /django_kss_project/django_kss_project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_kss_project project. 3 | 4 | For more information on this file, see 5 | https://docs.djangoproject.com/en/1.6/topics/settings/ 6 | 7 | For the full list of settings and their values, see 8 | https://docs.djangoproject.com/en/1.6/ref/settings/ 9 | """ 10 | 11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 12 | import os 13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__)) 14 | 15 | 16 | # Quick-start development settings - unsuitable for production 17 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ 18 | 19 | # SECURITY WARNING: keep the secret key used in production secret! 20 | SECRET_KEY = 'o&_8@#1cw8$2+%gr%%g_t$5y7+v((0#qzsc-f_x)4j#fiy(+75' 21 | 22 | # SECURITY WARNING: don't run with debug turned on in production! 23 | DEBUG = True 24 | 25 | TEMPLATE_DEBUG = True 26 | 27 | ALLOWED_HOSTS = ['*'] 28 | 29 | 30 | TEMPLATE_CONTEXT_PROCESSORS = ( 31 | 'django.contrib.auth.context_processors.auth', 32 | 'django.core.context_processors.debug', 33 | 'django.core.context_processors.i18n', 34 | 'django.core.context_processors.media', 35 | 'django.core.context_processors.static', 36 | 'django.core.context_processors.tz', 37 | 'django.contrib.messages.context_processors.messages', 38 | 'django.core.context_processors.request', 39 | ) 40 | # Application definition 41 | 42 | INSTALLED_APPS = ( 43 | 'django.contrib.admin', 44 | 'django.contrib.auth', 45 | 'django.contrib.contenttypes', 46 | 'django.contrib.sessions', 47 | 'django.contrib.messages', 48 | 'django.contrib.staticfiles', 49 | "compressor", 50 | 'django_kss', 51 | 'sample', 52 | 'sample2', 53 | ) 54 | 55 | MIDDLEWARE_CLASSES = ( 56 | 'django.contrib.sessions.middleware.SessionMiddleware', 57 | 'django.middleware.common.CommonMiddleware', 58 | 'django.middleware.csrf.CsrfViewMiddleware', 59 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 60 | 'django.contrib.messages.middleware.MessageMiddleware', 61 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 62 | ) 63 | 64 | ROOT_URLCONF = 'django_kss_project.urls' 65 | 66 | WSGI_APPLICATION = 'django_kss_project.wsgi.application' 67 | 68 | 69 | # Database 70 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases 71 | 72 | DATABASES = { 73 | 'default': { 74 | 'ENGINE': 'django.db.backends.sqlite3', 75 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 76 | } 77 | } 78 | 79 | # Internationalization 80 | # https://docs.djangoproject.com/en/1.6/topics/i18n/ 81 | 82 | LANGUAGE_CODE = 'en-us' 83 | 84 | TIME_ZONE = 'UTC' 85 | 86 | USE_I18N = True 87 | 88 | USE_L10N = True 89 | 90 | USE_TZ = True 91 | 92 | 93 | # Static files (CSS, JavaScript, Images) 94 | # https://docs.djangoproject.com/en/1.6/howto/static-files/ 95 | 96 | STATICFILES_DIRS = ( 97 | os.path.join(BASE_DIR, "static"), 98 | ) 99 | 100 | STATIC_URL = '/static/' 101 | 102 | 103 | COMPRESS_PRECOMPILERS = ( 104 | ('text/x-scss', 'django_libsass.SassCompiler'), 105 | ) 106 | STATICFILES_FINDERS = ( 107 | 'django.contrib.staticfiles.finders.FileSystemFinder', 108 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 109 | 'compressor.finders.CompressorFinder', 110 | ) 111 | # Django Compressor for development. so it can put image to correct place 112 | COMPRESS_ENABLED = True 113 | COMPRESS_REBUILD_TIMEOUT = 0 114 | 115 | STATIC_ROOT = '/tmp/root' -------------------------------------------------------------------------------- /django_kss/pykss/comment.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | single_line_re = re.compile(r'^\s*\/\/') 5 | single_line_strip_re = re.compile(r'\s*\/\/') 6 | 7 | multi_line_start_re = re.compile(r'^\s*\/\*') 8 | multi_line_end_re = re.compile(r'.*\*\/') 9 | multi_line_start_strip_re = re.compile(r'\s*\/\*') 10 | multi_line_end_strip_re = re.compile(r'\*\/') 11 | multi_line_middle_strip_re = re.compile(r'^(\s*\*+)') 12 | 13 | preceding_white_space_re = re.compile(r'^\s*') 14 | 15 | 16 | def is_single_line_comment(line): 17 | return single_line_re.match(line) is not None 18 | 19 | 20 | def is_multi_line_comment_start(line): 21 | return multi_line_start_re.match(line) is not None 22 | 23 | 24 | def is_multi_line_comment_end(line): 25 | if is_single_line_comment(line): 26 | return False 27 | return multi_line_end_re.match(line) is not None 28 | 29 | 30 | def parse_single_line(line): 31 | return single_line_strip_re.sub('', line).rstrip() 32 | 33 | 34 | def parse_multi_line(line): 35 | cleaned = multi_line_start_strip_re.sub('', line) 36 | return multi_line_end_strip_re.sub('', cleaned).rstrip() 37 | 38 | 39 | def normalize(lines): 40 | cleaned = [] 41 | indents = [] 42 | 43 | for line in lines: 44 | line = multi_line_middle_strip_re.sub('', line) 45 | cleaned.append(line) 46 | match = preceding_white_space_re.match(line) 47 | if line: 48 | indents.append(len(match.group())) 49 | 50 | indent = min(indents) if indents else 0 51 | 52 | return '\n'.join([line[indent:] for line in cleaned]).strip() 53 | 54 | 55 | class CommentParser(object): 56 | 57 | def __init__(self, filename): 58 | self.filename = filename 59 | 60 | def parse(self): 61 | blocks = [] 62 | current_block = [] 63 | inside_single_line_block = False 64 | inside_multi_line_block = False 65 | 66 | with open(self.filename) as fileobj: 67 | for line in fileobj: 68 | # Parse single-line style 69 | if is_single_line_comment(line): 70 | parsed = parse_single_line(line) 71 | 72 | if inside_single_line_block: 73 | current_block.append(parsed) 74 | else: 75 | current_block = [parsed] 76 | inside_single_line_block = True 77 | 78 | # Prase multi-line style 79 | if is_multi_line_comment_start(line) or inside_multi_line_block: 80 | parsed = parse_multi_line(line) 81 | 82 | if inside_multi_line_block: 83 | current_block.append(parsed) 84 | else: 85 | current_block = [parsed] 86 | inside_multi_line_block = True 87 | 88 | # End a multi-line block if detected 89 | if is_multi_line_comment_end(line): 90 | inside_multi_line_block = False 91 | 92 | # Store the current block if we're done 93 | if is_single_line_comment(line) is False and inside_multi_line_block is False: 94 | if current_block: 95 | blocks.append(normalize(current_block)) 96 | 97 | inside_single_line_block = False 98 | current_block = [] 99 | 100 | return blocks 101 | 102 | @property 103 | def blocks(self): 104 | if not hasattr(self, '_blocks'): 105 | self._blocks = self.parse() 106 | return self._blocks 107 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | ************ 3 | introduction 4 | ************ 5 | 6 | Help you launch your style guide site with django in KSS syntax. you can integrate the style giude in your site easily. 7 | I use it every day. feel free to give me any suggestion. 8 | 9 | I now change the name to django-kss-styleguide https://pypi.python.org/pypi/django-kss-styleguide/ 10 | 11 | .. image:: pictures/screenshot.png 12 | 13 | ===== 14 | start 15 | ===== 16 | 17 | pip install django-kss-styleguide 18 | 19 | 20 | 21 | ======== 22 | Settings 23 | ======== 24 | 25 | in yout settings.py 26 | 27 | Add the app, 28 | 29 | .. code-block:: python 30 | 31 | INSTALLED_APPS += ( 32 | "compressor", 33 | "django_kss", 34 | ) 35 | 36 | 37 | ================ 38 | Related Settings 39 | ================ 40 | 41 | in settings.py 42 | 43 | because scss is very common, we support it via djagno compressor 44 | Add setting about django compressor. 45 | 46 | .. code-block:: python 47 | 48 | COMPRESS_PRECOMPILERS = ( 49 | ('text/x-scss', 'django_libsass.SassCompiler'), 50 | ) 51 | STATICFILES_FINDERS = ( 52 | 'django.contrib.staticfiles.finders.FileSystemFinder', 53 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 54 | 'compressor.finders.CompressorFinder', 55 | ) 56 | # Django Compressor for development. so it can put image to correct place 57 | COMPRESS_ENABLED = True 58 | COMPRESS_REBUILD_TIMEOUT = 0 59 | 60 | STATIC_ROOT = '/tmp/root' 61 | 62 | in your app. 63 | 64 | add filename called styleguide.py in your app. 65 | 66 | .. code-block:: python 67 | 68 | styleguide = { 69 | 'source_dir': 'static/css', 70 | 'verbose_name': 'Sample APP2', #Optional 71 | 'target_files': 'static/css/form.scss' # optional 72 | } 73 | 74 | 75 | source_dir: Where you write you kss comment and css files 76 | 77 | verbose_name: Your app name 78 | 79 | target_files: If you use scss, put the scss file you want to compile 80 | 81 | 82 | urls.py settings 83 | ================ 84 | 85 | Routing, add the following two lines in your project's urls.py 86 | 87 | import: 88 | 89 | .. code-block:: python 90 | 91 | import django_kss.urls 92 | 93 | add the url patterns: 94 | 95 | .. code-block:: python 96 | 97 | url(r'^$', include(django_kss.urls)), 98 | 99 | 100 | 101 | html 102 | ==== 103 | 104 | for F2E or designer 105 | 106 | put your complete html in templates/prototype/ 107 | 108 | you can view it automatically in the site 109 | 110 | 111 | Writing The KSS in your scss/less/css file 112 | ========================================== 113 | 114 | 115 | .. code-block:: scss 116 | 117 | /* 118 | Buttons 119 | 120 | Styleguide 1 121 | */ 122 | 123 | 124 | /* 125 | Your standard form button. 126 | 127 | .btn-danger - danger 128 | .btn-warning - warning 129 | .btn-info - info 130 | 131 | 132 | Example: 133 | 134 | 135 | Styleguide 1.1 136 | */ 137 | 138 | .liftedBtn{ 139 | @extend .btn; 140 | position: relative; 141 | border-width: 0; 142 | letter-spacing: 1px; 143 | border-bottom-color: rgba(30,30,30,0.3); 144 | border-bottom-width: 0; 145 | transition: all 0.2s; 146 | bottom: 0; 147 | &:hover{ 148 | bottom: $strong-border-width; 149 | border-bottom-width: $strong-border-width; 150 | } 151 | } 152 | 153 | 154 | 155 | 156 | =============== 157 | One More Things 158 | =============== 159 | 160 | the base template is already integrate livereload. 161 | 162 | to utilize livereload, 163 | 164 | 165 | .. code-block:: bash 166 | 167 | sudo pip install livereload 168 | 169 | 170 | and type 'livereload .' in you repository root. 171 | 172 | you can see all the braowser will reflect your change 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /django_kss/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import imp 3 | import logging 4 | import os 5 | import os.path 6 | import sys 7 | from importlib import import_module 8 | from django.conf import settings 9 | 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | 14 | def _get_styleguide_module(module_name='styleguide'): 15 | 16 | style_guides = [] 17 | modules_to_check = [] 18 | 19 | # Hackish: do this in case we have some project top-level 20 | # (homepage, etc) urls defined project-level instead of app-level. 21 | settings_module = settings.SETTINGS_MODULE 22 | if settings_module: 23 | if "." in settings_module: 24 | # strip off '.settings" from end of module 25 | # (want project module, if possible) 26 | settings_module = settings_module.split(".", 1)[0] 27 | modules_to_check += [settings_module, ] 28 | 29 | # INSTALLED_APPS that aren't the project itself (also ignoring this 30 | # django_medusa module) 31 | modules_to_check += filter( 32 | lambda x: (x != "django_kss") and (x != settings_module), 33 | settings.INSTALLED_APPS 34 | ) 35 | 36 | for app in modules_to_check: 37 | try: 38 | import_module(app) 39 | app_path = sys.modules[app].__path__ 40 | except AttributeError: 41 | logger.debug("Skipping app '%s'... (Not found)", app) 42 | continue 43 | try: 44 | imp.find_module(module_name, app_path) 45 | except ImportError: 46 | logger.debug("Skipping app '%s'... (No 'styleguide.py')" , app) 47 | continue 48 | try: 49 | app_styleguide_module = import_module('%s.%s' % (app, module_name)) 50 | if hasattr(app_styleguide_module, "styleguide"): 51 | style_guides.append(app_styleguide_module) 52 | else: 53 | logger.debug("Skipping app '%s'... ('%s.styleguide' does not contain "\ 54 | "'styleguide' var (list of styleguide classes)" , (app, app)) 55 | except AttributeError: 56 | logger.debug("Skipping app '%s'... (Error importing '%s.styleguide')" , ( 57 | app, app 58 | )) 59 | continue 60 | logger.debug("Found styleguide for '%s'..." , app) 61 | return style_guides 62 | 63 | 64 | def _remove_static(target_file): 65 | if target_file.startswith('static/'): 66 | return target_file.replace('static/', '') 67 | return target_file 68 | 69 | 70 | def _complete_setting(m): 71 | app_path = os.path.dirname(m.__file__) 72 | 73 | try: 74 | source_dir = m.styleguide['source_dir'] 75 | except KeyError: 76 | source_dir = 'static/css' 77 | abs_source_dir = os.path.join(app_path, source_dir) 78 | print(source_dir) 79 | 80 | try: 81 | verbose_name = m.styleguide['verbose_name'] 82 | except KeyError: 83 | verbose_name = m.__name__ 84 | 85 | try: 86 | target_files = m.styleguide['target_files'] 87 | if isinstance(target_files, str): 88 | target_files = [target_files] 89 | except KeyError: 90 | target_files = os.listdir(abs_source_dir) 91 | target_files = map(lambda x: os.path.join(source_dir, x), target_files) 92 | 93 | try: 94 | htmls = os.listdir(os.path.join(app_path, 'templates', 'prototype')) 95 | except OSError: 96 | htmls = [] 97 | 98 | target_files = map(_remove_static, target_files) 99 | 100 | styleguide = m.styleguide.copy() 101 | styleguide['source_dir'] = abs_source_dir 102 | styleguide['app_name'] = m.__name__ 103 | styleguide['verbose_name'] = verbose_name 104 | styleguide['target_files'] = target_files 105 | styleguide['htmls'] = htmls 106 | return styleguide 107 | 108 | 109 | def get_styleguide(): 110 | safe_settings = map(_complete_setting, _get_styleguide_module()) 111 | setting_map = {} 112 | for setting in safe_settings: 113 | setting_map[setting['app_name']] = setting 114 | return setting_map 115 | 116 | 117 | -------------------------------------------------------------------------------- /django_kss/views.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from pygments.formatters import HtmlFormatter 3 | from django.utils.functional import cached_property 4 | 5 | from django import conf 6 | from django.views.generic.base import TemplateView 7 | from django.shortcuts import render 8 | 9 | 10 | from . import utils 11 | from . import pykss 12 | 13 | 14 | 15 | def render_prototype(request, html): 16 | prototype_directory = dirs = getattr(conf.settings, 'PROTOTYPR_DIR', "prototype") 17 | return render(request, "styleguide-full-content.html", 18 | { 'inline_content': os.path.join(prototype_directory, html)}) 19 | 20 | 21 | class StyleguideMixin(object): 22 | def get_styleguide(self): 23 | dirs = getattr(conf.settings, 'PYKSS_DIRS', []) 24 | return pykss.Parser(*dirs) 25 | 26 | def get_context_data(self, **kwargs): 27 | context = super(StyleguideMixin, self).get_context_data(**kwargs) 28 | context.update({'styleguide': self.get_styleguide()}) 29 | return context 30 | 31 | 32 | class StyleguideView(StyleguideMixin, TemplateView): 33 | pass 34 | 35 | 36 | class AutoStyleGuideView(TemplateView): 37 | 38 | def styleguide_settings(self, settings): 39 | return settings.items() 40 | 41 | def domain(self): 42 | host = self.request.META['HTTP_HOST'] 43 | domain = host.split(":")[0] 44 | return domain 45 | 46 | def _get_settings(self): 47 | return utils.get_styleguide() 48 | 49 | def _get_setting(self, settings): 50 | try: 51 | app_name = self.kwargs['app_name'] 52 | return settings[app_name] 53 | except KeyError: 54 | return settings.values()[0] 55 | 56 | def get_styleguide(self, settings): 57 | setting = self._get_setting(settings) 58 | return pykss.Parser(setting['source_dir']) 59 | 60 | def css_source_files(self, settings): 61 | return map(lambda fn: [fn, fn.endswith('scss')], self._get_setting(settings)['target_files']) 62 | 63 | @cached_property 64 | def pygament_style(self): 65 | return HtmlFormatter().get_style_defs('.highlight') 66 | 67 | def get_context_data(self, **kwargs): 68 | 69 | context = super(AutoStyleGuideView, self).get_context_data(**kwargs) 70 | 71 | settings = self._get_settings() 72 | context.update({'styleguide': self.get_styleguide(settings)}) 73 | context.update({'styleguide_settings': self.styleguide_settings(settings)}) 74 | context.update({'css_source_files': self.css_source_files(settings)}) 75 | 76 | styleguide = context["styleguide"] 77 | file_names = set(map(lambda section: section.filename, styleguide.sections.values())) 78 | 79 | if 'section' not in self.kwargs or not self.kwargs['section']: 80 | current_section = styleguide.sections.values()[0].section 81 | else: 82 | target_filename = self.kwargs['section'] 83 | possible = filter(lambda section: section.filename == target_filename, styleguide.sections.values()) 84 | current_section = possible[0].section 85 | current_section_prefix = current_section.split(".")[0] 86 | 87 | context.update({'app_name': self._get_setting(settings)['app_name']}) 88 | context.update({'current_section': current_section_prefix}) 89 | context.update({'file_names': file_names}) 90 | context.update({'htmls': self._get_setting(settings)['htmls']}) 91 | return context 92 | 93 | 94 | class InlineTemplateStyleGuideView(AutoStyleGuideView): 95 | 96 | template_name = 'styleguide-inline-content.html' 97 | 98 | def get_context_data(self, **kwargs): 99 | context = super(InlineTemplateStyleGuideView, self).get_context_data(**kwargs) 100 | context.update({'inline_content': 'prototype/' + self.kwargs['html']}) 101 | context.update({'html': self.kwargs['html']}) 102 | return context 103 | 104 | class FullTemplateStyleGuideView(AutoStyleGuideView): 105 | 106 | template_name = 'styleguide-full-content.html' 107 | 108 | def get_context_data(self, **kwargs): 109 | context = super(FullTemplateStyleGuideView, self).get_context_data(**kwargs) 110 | context.update({'inline_content': 'prototype/' + self.kwargs['html']}) 111 | return context 112 | -------------------------------------------------------------------------------- /django_kss/templatetags/pykss.py: -------------------------------------------------------------------------------- 1 | from django.template.loader import render_to_string 2 | from django import template 3 | from pygments import highlight 4 | from pygments.lexers import get_lexer_by_name 5 | from pygments.formatters import HtmlFormatter 6 | 7 | from pygments.util import ClassNotFound 8 | 9 | 10 | register = template.Library() 11 | 12 | 13 | @register.filter(name='highlight_code') 14 | def highlight_code(code, lang): 15 | if code is not None: 16 | try: 17 | lexer = get_lexer_by_name(lang, encoding='utf-8', stripall=True, startinline=True) 18 | except ClassNotFound: 19 | lexer = get_lexer_by_name('text') 20 | formatter = HtmlFormatter(encoding='utf-8', style='colorful', cssclass='highlight', 21 | lineanchors="line") 22 | return highlight(code, lexer, formatter) 23 | else: 24 | return code 25 | 26 | 27 | class BaseStyleguideNode(template.Node): 28 | 29 | def __init__(self, styleguide, reference, template_name, nodelist): 30 | self.styleguide = styleguide 31 | self.reference = reference 32 | self.template_name = template_name 33 | self.nodelist = nodelist 34 | 35 | def __repr__(self): 36 | return '' 37 | 38 | @classmethod 39 | def as_tag(cls, parser, token): 40 | bits = token.split_contents()[1:] 41 | 42 | if len(bits) < 2: 43 | raise template.TemplateSyntaxError("styleguideblock expected at " 44 | "least two arguments") 45 | 46 | elif len(bits) == 2: 47 | styleguide, reference = bits 48 | template_name = '"pykss/styleguideblock.html"' 49 | 50 | elif len(bits) >= 3 and bits[2] != 'using': 51 | raise template.TemplateSyntaxError("styleguideblock expected using " 52 | "as the third argument") 53 | 54 | elif len(bits) == 3: 55 | raise template.TemplateSyntaxError("styleguideblock expects a " 56 | "template name after 'using'") 57 | 58 | else: 59 | styleguide, reference, _using, template_name = bits 60 | 61 | return cls.dispatch(parser, styleguide, reference, template_name) 62 | 63 | @classmethod 64 | def dispatch(cls, parser, styleguide, reference, template_name): 65 | raise NotImplementedError 66 | 67 | def render(self, context): 68 | styleguide = self.styleguide.resolve(context) 69 | reference = self.reference.resolve(context) 70 | template_name = self.template_name.resolve(context) 71 | 72 | sections = sorted([sec for ref, sec in styleguide.sections.iteritems() 73 | if ref.startswith(reference)], key=lambda s: s.section) 74 | 75 | if self.nodelist: 76 | example = self.nodelist.render(context).strip() 77 | for section in sections: 78 | section.add_example(example) 79 | 80 | output = [] 81 | 82 | for section in sections: 83 | context.update({'section': section}) 84 | html = render_to_string(template_name, context) 85 | output.append(html) 86 | context.pop() 87 | 88 | return ''.join(output) 89 | 90 | 91 | class StyleguideBlockNode(BaseStyleguideNode): 92 | 93 | @classmethod 94 | def dispatch(cls, parser, styleguide, reference, template_name): 95 | nodelist = parser.parse(('endstyleguideblock',)) 96 | parser.delete_first_token() 97 | return cls( 98 | styleguide=parser.compile_filter(styleguide), 99 | reference=parser.compile_filter(reference), 100 | template_name=parser.compile_filter(template_name), 101 | nodelist=nodelist, 102 | ) 103 | 104 | 105 | class RenderStyleguideNode(BaseStyleguideNode): 106 | 107 | @classmethod 108 | def dispatch(cls, parser, styleguide, reference, template_name): 109 | return cls( 110 | styleguide=parser.compile_filter(styleguide), 111 | reference=parser.compile_filter(reference), 112 | template_name=parser.compile_filter(template_name), 113 | nodelist=None, 114 | ) 115 | 116 | 117 | @register.tag 118 | def styleguideblock(parser, token): 119 | """ 120 | {% styleguideblock styleguide "1.1" %} 121 | 122 | {% endstyleguideblock %} 123 | 124 | {% styleguideblock styleguide "1.1" using "custom.html" %} 125 | 126 | {% endstyleguideblock %} 127 | 128 | """ 129 | return StyleguideBlockNode.as_tag(parser, token) 130 | 131 | 132 | @register.tag 133 | def renderstyleguide(parser, token): 134 | """ 135 | {% renderstyleguide styleguide "1.1" %} 136 | 137 | {% renderstyleguide styleguide "1.1" using "custom.html" %} 138 | """ 139 | return RenderStyleguideNode.as_tag(parser, token) 140 | -------------------------------------------------------------------------------- /django_kss/static/css/layout.css: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | @group Global Reset 3 | ----------------------------------------------------------------------------*/ 4 | /* 5 | 6 | .access{ display:none; } /* For accessibility related elements */ 7 | 8 | .clear{ clear:both; height:0px; font-size:0px; line-height:0px; overflow:hidden; } 9 | 10 | 11 | @media (max-width: 767px) { 12 | .styleguide-hidden-xs { 13 | display: none !important; 14 | } 15 | } 16 | 17 | /* 18 | .styleguide-header{ 19 | padding:10px; 20 | 21 | font-size:16px; 22 | color:#666; 23 | 24 | background:#f1f1f1; 25 | border-bottom:1px solid #ddd; 26 | font-weight: bold; 27 | } 28 | */ 29 | 30 | #wrapper{ 31 | min-width:600px; 32 | padding-left:200px; 33 | } 34 | @media (max-width: 767px) { 35 | .styleguide-hidden-xs { 36 | display: none !important; 37 | } 38 | #wrapper{ 39 | width:100%; 40 | max-width: 100%; 41 | min-width: 0; 42 | padding-left: 0; 43 | } 44 | } 45 | 46 | [role=main]{ 47 | float:left; 48 | margin-left:-200px; 49 | width:160px; 50 | } 51 | 52 | 53 | /*---------------------------------------------------------------------------- 54 | @group Styleguide Styles 55 | ----------------------------------------------------------------------------*/ 56 | 57 | .styleguide { 58 | margin: 0 0 -5px 0; 59 | font-size: 24px; 60 | color: #000; } 61 | 62 | .styleguide-example { 63 | margin: 15px 0; 64 | background: rgba(255, 255, 255, 0.5); 65 | border: 1px solid #ddd; 66 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); } 67 | .styleguide-example > h3 { 68 | margin: 0; 69 | padding: 5px; 70 | color: #fff; 71 | font-size: 12px; 72 | text-transform: uppercase; 73 | background: #333; 74 | border-top: 1px solid #000; } 75 | .styleguide-example > h3 em { 76 | float: right; 77 | text-transform: none; 78 | font-style: normal; 79 | font-weight: normal; 80 | color: #999; } 81 | .styleguide-example .styleguide-description { 82 | padding: 10px 5px; 83 | background: #f1f1f1; 84 | border-bottom: 1px solid #ddd; } 85 | .styleguide-example .styleguide-description p:first-child { 86 | margin-top: 0; } 87 | .styleguide-example .styleguide-description p:last-child { 88 | margin-bottom: 0; } 89 | .styleguide-example .styleguide-element { 90 | position: relative; 91 | padding: 20px; } 92 | .styleguide-example .styleguide-element + .styleguide-element { 93 | margin-top: -5px; 94 | padding-top: 15px; 95 | border-top: 1px solid #eee; } 96 | .styleguide-example .styleguide-element .styleguide-modifier-name { 97 | display: block; 98 | background-color: rgba(0,0,0,0.5); 99 | /* position: absolute; */ 100 | /* top: 0; */ 101 | /* right: 0; */ 102 | /* padding: 5px 8px; */ 103 | font-size: 14px; 104 | color: gray; 105 | background: rgba(0,0,0,0.1); 106 | border: 1px solid #eee; 107 | border-top: none; 108 | } 109 | .styleguide-example .styleguide-html { 110 | padding: 5px 10px; 111 | background: #edf6f8; 112 | border-top: 1px solid #dde7ea; 113 | overflow: auto; } 114 | .styleguide-example .styleguide-html .highlight { 115 | background: none; } 116 | .styleguide-example ul.styleguide-modifiers { 117 | margin: 0 0 0 10px; } 118 | .styleguide-example ul.styleguide-modifiers li { 119 | list-style-type: none; 120 | margin-left: 0; } 121 | .styleguide-example ul.styleguide-modifiers li strong { 122 | font-family: Monaco, monospace; 123 | font-size: 12px; 124 | font-weight: normal; 125 | color: #222; } 126 | .styleguide-example > .styleguide-code { 127 | font-family: Monaco, monospace; 128 | } 129 | 130 | .styleguide-modifier li{ 131 | } 132 | 133 | .styleguide-nav{ 134 | box-sizing: border-box; 135 | color: rgb(51, 51, 51); 136 | display: block; 137 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 138 | font-size: 14px; 139 | height: 124px; 140 | line-height: 20px; 141 | list-style-image: none; 142 | list-style-position: outside; 143 | list-style-type: none; 144 | margin-bottom: 0px; 145 | margin-top: 0px; 146 | max-width: 300px; 147 | padding-left: 0px; 148 | } 149 | 150 | .styleguide-nav-list{ 151 | box-sizing: border-box; 152 | color: rgb(51, 51, 51); 153 | display: block; 154 | float: none; 155 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 156 | font-size: 14px; 157 | min-height: 40px; 158 | line-height: 20px; 159 | list-style-image: none; 160 | list-style-position: outside; 161 | list-style-type: none; 162 | margin-left: 0px; 163 | position: relative; 164 | } 165 | 166 | .styleguid-nav-anchor{ 167 | background-color: rgb(238, 238, 238); 168 | border-bottom-left-radius: 0; 169 | border-bottom-right-radius: 0; 170 | border-top-left-radius: 0; 171 | border-top-right-radius: 0; 172 | box-sizing: border-box; 173 | color: rgb(42, 100, 150); 174 | display: block; 175 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 176 | font-size: 14px; 177 | min-height: 40px; 178 | line-height: 20px; 179 | list-style-image: none; 180 | list-style-position: outside; 181 | list-style-type: none; 182 | outline-color: rgb(42, 100, 150); 183 | outline-style: none; 184 | outline-width: 0px; 185 | padding-bottom: 10px; 186 | padding-left: 15px; 187 | padding-right: 15px; 188 | padding-top: 10px; 189 | position: relative; 190 | text-decoration: none; 191 | } 192 | .active .styleguid-nav-anchor{ 193 | background-color: rgb(66, 139, 202); 194 | box-sizing: border-box; 195 | color: rgb(255, 255, 255); 196 | display: block; 197 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 198 | font-size: 14px; 199 | height: 40px; 200 | line-height: 20px; 201 | list-style-image: none; 202 | list-style-position: outside; 203 | list-style-type: none; 204 | padding-bottom: 10px; 205 | padding-left: 15px; 206 | padding-right: 15px; 207 | padding-top: 10px; 208 | position: relative; 209 | text-decoration: none; 210 | } 211 | /* @end */ 212 | 213 | 214 | .styleguide-element{ 215 | background-image: url(data:image/png;base64,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); 216 | } 217 | 218 | .styleguide-header .brand{ 219 | background-color: #444; 220 | float: left; 221 | font-size: 1.2em; 222 | margin-left: 20px; 223 | color: #fff; 224 | } 225 | 226 | .styleguide-header .nav ul { 227 | list-style: none; 228 | background-color: #444; 229 | text-align: center; 230 | padding: 0; 231 | margin: 0; 232 | } 233 | .styleguide-header .nav li { 234 | font-family: 'Oswald', sans-serif; 235 | font-size: 1.2em; 236 | line-height: 40px; 237 | height: 40px; 238 | border-bottom: 1px solid #888; 239 | } 240 | 241 | .styleguide-header .nav a { 242 | text-decoration: none; 243 | color: #fff; 244 | display: block; 245 | transition: .3s background-color; 246 | padding-left: 10px; 247 | padding-right: 10px; 248 | } 249 | 250 | .styleguide-header .nav a:hover, .styleguide-header .nav .active { 251 | background-color: #005f5f; 252 | } 253 | 254 | .styleguide-header .nav a.active { 255 | background-color: #fff; 256 | color: #444; 257 | cursor: default; 258 | } 259 | 260 | @media screen and (min-width: 600px) { 261 | .styleguide-header .nav li , .styleguide-header .nav .brand{ 262 | min-width: 120px; 263 | border-bottom: none; 264 | height: 50px; 265 | line-height: 50px; 266 | font-size: 1.4em; 267 | } 268 | 269 | /* Option 1 - Display Inline */ 270 | .styleguide-header .nav li { 271 | display: inline-block; 272 | margin-right: -4px; 273 | margin-left: 10px; 274 | } 275 | 276 | /* Options 2 - Float 277 | .nav li { 278 | float: left; 279 | } 280 | .nav ul { 281 | overflow: auto; 282 | width: 600px; 283 | margin: 0 auto; 284 | } 285 | .nav { 286 | background-color: #444; 287 | } 288 | */ 289 | } 290 | --------------------------------------------------------------------------------