diff options
| -rw-r--r-- | Dockerfile | 5 | ||||
| -rw-r--r-- | cgitrc | 2 | ||||
| -rw-r--r-- | responsive/cgit.css | 359 | ||||
| -rwxr-xr-x | responsive/md2html | 37 | ||||
| -rwxr-xr-x | responsive/syntax-material.py | 37 |
5 files changed, 423 insertions, 17 deletions
| @@ -15,11 +15,14 @@ RUN make install | |||
| 15 | COPY cgitrc /app | 15 | COPY cgitrc /app |
| 16 | COPY responsive/head.html /app/www/static | 16 | COPY responsive/head.html /app/www/static |
| 17 | COPY responsive/cgit.css /app/www/static | 17 | COPY responsive/cgit.css /app/www/static |
| 18 | COPY responsive/syntax-material.py /app/lib/filters | ||
| 19 | COPY responsive/md2html /app/lib/filters/html-converters/md2html | ||
| 18 | 20 | ||
| 19 | FROM debian:latest AS cgit-run | 21 | FROM debian:latest AS cgit-run |
| 20 | 22 | ||
| 21 | RUN apt-get update | 23 | RUN apt-get update |
| 22 | RUN apt-get install -y python3 python3-pygments lighttpd | 24 | RUN apt-get install -y python3 python3-pygments python3-markdown python3-docutils |
| 25 | RUN apt-get install -y lighttpd | ||
| 23 | 26 | ||
| 24 | WORKDIR /app | 27 | WORKDIR /app |
| 25 | COPY --from=cgit-build /app /app | 28 | COPY --from=cgit-build /app /app |
| @@ -5,6 +5,6 @@ favicon=/static/favicon.ico | |||
| 5 | head-include=/app/www/static/head.html | 5 | head-include=/app/www/static/head.html |
| 6 | 6 | ||
| 7 | about-filter=/app/lib/filters/about-formatting.sh | 7 | about-filter=/app/lib/filters/about-formatting.sh |
| 8 | source-filter=/app/lib/filters/syntax-highlighting.py | 8 | source-filter=/app/lib/filters/syntax-material.py |
| 9 | 9 | ||
| 10 | include=/app/etc/cgitrc | 10 | include=/app/etc/cgitrc |
diff --git a/responsive/cgit.css b/responsive/cgit.css index f9e1b76..c69b01c 100644 --- a/responsive/cgit.css +++ b/responsive/cgit.css | |||
| @@ -556,27 +556,356 @@ div#cgit div.error { | |||
| 556 | } | 556 | } |
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | /* --- Fix Syntax Highlighting Alignment --- */ | 559 | /* Container override for highlighted code to handle font sizing */ |
| 560 | div#cgit table.blob pre { | ||
| 561 | font-family: "JetBrains Mono", "Fira Code", monospace; | ||
| 562 | font-size: 0.95em; | ||
| 563 | line-height: 1.4; | ||
| 564 | } | ||
| 560 | 565 | ||
| 561 | /* 1. Reset margins and padding added by syntax highlighting */ | 566 | /* --- Syntax Highlighting Mapping to Material Variables --- */ |
| 562 | div#cgit table.blob td.lines div.highlight { | 567 | |
| 563 | margin: 0; | 568 | /* Comments - Outline/Grey */ |
| 564 | padding: 0; | 569 | .hl-c, |
| 565 | border: none; | 570 | .hl-cm, |
| 571 | .hl-cp, | ||
| 572 | .hl-c1, | ||
| 573 | .hl-cs { | ||
| 574 | color: var(--color-outline); | ||
| 575 | font-style: italic; | ||
| 566 | } | 576 | } |
| 567 | 577 | ||
| 568 | /* 2. Force alignment of line height and fonts */ | 578 | /* Keywords - Primary (Pinkish/Orange) */ |
| 569 | div#cgit table.blob td.linenumbers pre, | 579 | .hl-k, |
| 570 | div#cgit table.blob td.lines pre { | 580 | .hl-kc, |
| 571 | font-family: monospace; | 581 | .hl-kd, |
| 572 | font-size: 14px; | 582 | .hl-kn, |
| 573 | line-height: 1.5 !important; | 583 | .hl-kp, |
| 584 | .hl-kr, | ||
| 585 | .hl-kt { | ||
| 586 | color: var(--color-primary); | ||
| 587 | font-weight: bold; | ||
| 588 | } | ||
| 589 | |||
| 590 | /* Names/Functions - Tertiary (Yellowish) */ | ||
| 591 | .hl-n, | ||
| 592 | .hl-na, | ||
| 593 | .hl-nb, | ||
| 594 | .hl-nc, | ||
| 595 | .hl-no, | ||
| 596 | .hl-nd, | ||
| 597 | .hl-ni, | ||
| 598 | .hl-ne, | ||
| 599 | .hl-nf, | ||
| 600 | .hl-nl, | ||
| 601 | .hl-nn, | ||
| 602 | .hl-nt, | ||
| 603 | .hl-nv, | ||
| 604 | .hl-nx { | ||
| 605 | color: var(--color-tertiary); | ||
| 606 | } | ||
| 607 | |||
| 608 | /* Strings - Secondary (Reddish/Brownish) */ | ||
| 609 | .hl-s, | ||
| 610 | .hl-sa, | ||
| 611 | .hl-sb, | ||
| 612 | .hl-sc, | ||
| 613 | .hl-dl, | ||
| 614 | .hl-sd, | ||
| 615 | .hl-s2, | ||
| 616 | .hl-se, | ||
| 617 | .hl-sh, | ||
| 618 | .hl-si, | ||
| 619 | .hl-sx, | ||
| 620 | .hl-sr, | ||
| 621 | .hl-s1, | ||
| 622 | .hl-ss { | ||
| 623 | color: var(--color-secondary); | ||
| 624 | } | ||
| 625 | |||
| 626 | /* Operators - On Surface (Main text color) */ | ||
| 627 | .hl-o, | ||
| 628 | .hl-ow { | ||
| 629 | color: var(--color-on-surface-variant); | ||
| 630 | } | ||
| 631 | |||
| 632 | /* Numbers - Primary Container (Brighter accent) */ | ||
| 633 | .hl-m, | ||
| 634 | .hl-mb, | ||
| 635 | .hl-mf, | ||
| 636 | .hl-mh, | ||
| 637 | .hl-mi, | ||
| 638 | .hl-mo, | ||
| 639 | .hl-il { | ||
| 640 | color: var(--color-primary-fixed); | ||
| 641 | } | ||
| 642 | |||
| 643 | /* Errors */ | ||
| 644 | .hl-err, | ||
| 645 | .hl-gr { | ||
| 646 | color: var(--color-error); | ||
| 647 | background-color: var(--color-error-container); | ||
| 648 | } | ||
| 649 | |||
| 650 | /* Generic Deleted */ | ||
| 651 | .hl-gd { | ||
| 652 | color: var(--color-error); | ||
| 653 | background-color: var(--color-error-container); | ||
| 654 | } | ||
| 655 | |||
| 656 | /* Generic Inserted */ | ||
| 657 | .hl-gi { | ||
| 658 | color: var(--color-tertiary); | ||
| 659 | background-color: var(--color-tertiary-container); | ||
| 660 | } | ||
| 661 | |||
| 662 | /* --- Markdown Body Styles (Material Design) --- */ | ||
| 663 | |||
| 664 | .markdown-body { | ||
| 665 | font-family: inherit; | ||
| 666 | font-size: 1rem; | ||
| 667 | line-height: 1.6; | ||
| 668 | color: var(--color-on-background); | ||
| 669 | word-wrap: break-word; | ||
| 670 | } | ||
| 671 | |||
| 672 | /* Headers */ | ||
| 673 | .markdown-body h1, | ||
| 674 | .markdown-body h2, | ||
| 675 | .markdown-body h3, | ||
| 676 | .markdown-body h4, | ||
| 677 | .markdown-body h5, | ||
| 678 | .markdown-body h6 { | ||
| 679 | margin-top: 24px; | ||
| 680 | margin-bottom: 16px; | ||
| 681 | font-weight: 600; | ||
| 682 | line-height: 1.25; | ||
| 683 | color: var(--color-on-surface); | ||
| 684 | } | ||
| 685 | |||
| 686 | .markdown-body h1 { | ||
| 687 | font-size: 2em; | ||
| 688 | border-bottom: 1px solid var(--color-outline-variant); | ||
| 689 | padding-bottom: 0.3em; | ||
| 690 | } | ||
| 691 | .markdown-body h2 { | ||
| 692 | font-size: 1.5em; | ||
| 693 | border-bottom: 1px solid var(--color-outline-variant); | ||
| 694 | padding-bottom: 0.3em; | ||
| 695 | } | ||
| 696 | .markdown-body h3 { | ||
| 697 | font-size: 1.25em; | ||
| 698 | } | ||
| 699 | .markdown-body h4 { | ||
| 700 | font-size: 1em; | ||
| 701 | } | ||
| 702 | .markdown-body h5 { | ||
| 703 | font-size: 0.875em; | ||
| 704 | } | ||
| 705 | .markdown-body h6 { | ||
| 706 | font-size: 0.85em; | ||
| 707 | color: var(--color-on-surface-variant); | ||
| 708 | } | ||
| 709 | |||
| 710 | /* Links */ | ||
| 711 | .markdown-body a { | ||
| 712 | color: var(--color-primary); | ||
| 713 | text-decoration: none; | ||
| 714 | } | ||
| 715 | .markdown-body a:hover { | ||
| 716 | text-decoration: underline; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* Paragraphs & Lists */ | ||
| 720 | .markdown-body p, | ||
| 721 | .markdown-body blockquote, | ||
| 722 | .markdown-body ul, | ||
| 723 | .markdown-body ol, | ||
| 724 | .markdown-body dl, | ||
| 725 | .markdown-body table, | ||
| 726 | .markdown-body pre { | ||
| 574 | margin-top: 0; | 727 | margin-top: 0; |
| 728 | margin-bottom: 16px; | ||
| 575 | } | 729 | } |
| 576 | 730 | ||
| 577 | /* 3. Remove impact of first <pre> */ | 731 | .markdown-body hr { |
| 578 | div#cgit table.blob td.lines > pre { | 732 | height: 0.25em; |
| 579 | white-space: normal; | 733 | padding: 0; |
| 734 | margin: 24px 0; | ||
| 735 | background-color: var(--color-outline-variant); | ||
| 736 | border: 0; | ||
| 737 | } | ||
| 738 | |||
| 739 | /* Blockquotes */ | ||
| 740 | .markdown-body blockquote { | ||
| 741 | padding: 0 1em; | ||
| 742 | color: var(--color-on-surface-variant); | ||
| 743 | border-left: 0.25em solid var(--color-outline); | ||
| 744 | background-color: var(--color-surface-container-low); | ||
| 745 | } | ||
| 746 | |||
| 747 | /* Tables */ | ||
| 748 | .markdown-body table { | ||
| 749 | display: block; | ||
| 750 | width: 100%; | ||
| 751 | overflow: auto; | ||
| 752 | border-spacing: 0; | ||
| 753 | border-collapse: collapse; | ||
| 754 | } | ||
| 755 | |||
| 756 | .markdown-body table th { | ||
| 757 | font-weight: 600; | ||
| 758 | background-color: var(--color-surface-container); | ||
| 759 | } | ||
| 760 | |||
| 761 | .markdown-body table th, | ||
| 762 | .markdown-body table td { | ||
| 763 | padding: 6px 13px; | ||
| 764 | border: 1px solid var(--color-outline-variant); | ||
| 765 | } | ||
| 766 | |||
| 767 | .markdown-body table tr { | ||
| 768 | background-color: var(--color-surface); | ||
| 769 | border-top: 1px solid var(--color-outline-variant); | ||
| 770 | } | ||
| 771 | |||
| 772 | .markdown-body table tr:nth-child(2n) { | ||
| 773 | background-color: var(--color-surface-container-lowest); | ||
| 774 | } | ||
| 775 | |||
| 776 | /* Images */ | ||
| 777 | .markdown-body img { | ||
| 778 | max-width: 100%; | ||
| 779 | box-sizing: border-box; | ||
| 780 | background-color: var(--color-surface); | ||
| 781 | border-radius: 4px; | ||
| 782 | } | ||
| 783 | |||
| 784 | /* Code Blocks & Inline Code */ | ||
| 785 | .markdown-body code, | ||
| 786 | .markdown-body tt { | ||
| 787 | padding: 0.2em 0.4em; | ||
| 580 | margin: 0; | 788 | margin: 0; |
| 789 | font-size: 85%; | ||
| 790 | font-family: "JetBrains Mono", "Fira Code", monospace; | ||
| 791 | background-color: var(--color-surface-container-high); | ||
| 792 | border-radius: 6px; | ||
| 793 | color: var(--color-on-surface); | ||
| 794 | } | ||
| 795 | |||
| 796 | .markdown-body pre { | ||
| 797 | padding: 16px; | ||
| 798 | overflow: auto; | ||
| 799 | font-size: 85%; | ||
| 800 | line-height: 1.45; | ||
| 801 | background-color: var(--color-surface-container-lowest); | ||
| 802 | border-radius: 6px; | ||
| 803 | border: 1px solid var(--color-outline-variant); | ||
| 804 | } | ||
| 805 | |||
| 806 | .markdown-body pre code, | ||
| 807 | .markdown-body pre tt { | ||
| 808 | display: inline; | ||
| 809 | max-width: auto; | ||
| 581 | padding: 0; | 810 | padding: 0; |
| 811 | margin: 0; | ||
| 812 | overflow: visible; | ||
| 813 | line-height: inherit; | ||
| 814 | word-wrap: normal; | ||
| 815 | background-color: transparent; | ||
| 816 | border: 0; | ||
| 817 | } | ||
| 818 | |||
| 819 | /* Anchors (Permalinks) */ | ||
| 820 | .markdown-body .headerlink { | ||
| 821 | float: left; | ||
| 822 | padding-right: 4px; | ||
| 823 | margin-left: -20px; | ||
| 824 | line-height: 1; | ||
| 825 | color: var(--color-primary); | ||
| 826 | text-decoration: none; | ||
| 827 | opacity: 0; | ||
| 828 | transition: opacity 0.2s; | ||
| 829 | } | ||
| 830 | |||
| 831 | .markdown-body h1:hover .headerlink, | ||
| 832 | .markdown-body h2:hover .headerlink, | ||
| 833 | .markdown-body h3:hover .headerlink, | ||
| 834 | .markdown-body h4:hover .headerlink, | ||
| 835 | .markdown-body h5:hover .headerlink, | ||
| 836 | .markdown-body h6:hover .headerlink { | ||
| 837 | opacity: 1; | ||
| 838 | } | ||
| 839 | |||
| 840 | /* Pygments Syntax Highlighting within Markdown | ||
| 841 | (Mapping standard Pygments classes to Material Variables) */ | ||
| 842 | .markdown-body .highlight .c, | ||
| 843 | .markdown-body .highlight .cm, | ||
| 844 | .markdown-body .highlight .cp, | ||
| 845 | .markdown-body .highlight .c1, | ||
| 846 | .markdown-body .highlight .cs { | ||
| 847 | color: var(--color-outline); | ||
| 848 | font-style: italic; | ||
| 849 | } | ||
| 850 | .markdown-body .highlight .k, | ||
| 851 | .markdown-body .highlight .kc, | ||
| 852 | .markdown-body .highlight .kd, | ||
| 853 | .markdown-body .highlight .kn, | ||
| 854 | .markdown-body .highlight .kp, | ||
| 855 | .markdown-body .highlight .kr, | ||
| 856 | .markdown-body .highlight .kt { | ||
| 857 | color: var(--color-primary); | ||
| 858 | font-weight: bold; | ||
| 859 | } | ||
| 860 | .markdown-body .highlight .n, | ||
| 861 | .markdown-body .highlight .na, | ||
| 862 | .markdown-body .highlight .nb, | ||
| 863 | .markdown-body .highlight .nc, | ||
| 864 | .markdown-body .highlight .no, | ||
| 865 | .markdown-body .highlight .nd, | ||
| 866 | .markdown-body .highlight .ni, | ||
| 867 | .markdown-body .highlight .ne, | ||
| 868 | .markdown-body .highlight .nf, | ||
| 869 | .markdown-body .highlight .nl, | ||
| 870 | .markdown-body .highlight .nn, | ||
| 871 | .markdown-body .highlight .nt, | ||
| 872 | .markdown-body .highlight .nv, | ||
| 873 | .markdown-body .highlight .nx { | ||
| 874 | color: var(--color-tertiary); | ||
| 875 | } | ||
| 876 | .markdown-body .highlight .s, | ||
| 877 | .markdown-body .highlight .sa, | ||
| 878 | .markdown-body .highlight .sb, | ||
| 879 | .markdown-body .highlight .sc, | ||
| 880 | .markdown-body .highlight .dl, | ||
| 881 | .markdown-body .highlight .sd, | ||
| 882 | .markdown-body .highlight .s2, | ||
| 883 | .markdown-body .highlight .se, | ||
| 884 | .markdown-body .highlight .sh, | ||
| 885 | .markdown-body .highlight .si, | ||
| 886 | .markdown-body .highlight .sx, | ||
| 887 | .markdown-body .highlight .sr, | ||
| 888 | .markdown-body .highlight .s1, | ||
| 889 | .markdown-body .highlight .ss { | ||
| 890 | color: var(--color-secondary); | ||
| 891 | } | ||
| 892 | .markdown-body .highlight .m, | ||
| 893 | .markdown-body .highlight .mb, | ||
| 894 | .markdown-body .highlight .mf, | ||
| 895 | .markdown-body .highlight .mh, | ||
| 896 | .markdown-body .highlight .mi, | ||
| 897 | .markdown-body .highlight .mo, | ||
| 898 | .markdown-body .highlight .il { | ||
| 899 | color: var(--color-primary-fixed); | ||
| 900 | } | ||
| 901 | .markdown-body .highlight .o, | ||
| 902 | .markdown-body .highlight .ow { | ||
| 903 | color: var(--color-on-surface-variant); | ||
| 904 | } | ||
| 905 | .markdown-body .highlight .g, | ||
| 906 | .markdown-body .highlight .gh, | ||
| 907 | .markdown-body .highlight .gu, | ||
| 908 | .markdown-body .highlight .gd, | ||
| 909 | .markdown-body .highlight .gi { | ||
| 910 | color: var(--color-on-surface); | ||
| 582 | } | 911 | } |
diff --git a/responsive/md2html b/responsive/md2html new file mode 100755 index 0000000..571c8d7 --- /dev/null +++ b/responsive/md2html | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | import io | ||
| 3 | import sys | ||
| 4 | |||
| 5 | import markdown | ||
| 6 | from markdown.extensions.toc import TocExtension | ||
| 7 | |||
| 8 | sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding="utf-8") | ||
| 9 | sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") | ||
| 10 | |||
| 11 | sys.stdout.write("<div class='markdown-body'>") | ||
| 12 | sys.stdout.flush() | ||
| 13 | |||
| 14 | try: | ||
| 15 | markdown.markdownFromFile( | ||
| 16 | output_format="html5", | ||
| 17 | extensions=[ | ||
| 18 | "markdown.extensions.fenced_code", | ||
| 19 | "markdown.extensions.codehilite", | ||
| 20 | "markdown.extensions.tables", | ||
| 21 | "markdown.extensions.sane_lists", | ||
| 22 | "markdown.extensions.admonition", | ||
| 23 | TocExtension(anchorlink=True, permalink=True), | ||
| 24 | ], | ||
| 25 | extension_configs={ | ||
| 26 | "markdown.extensions.codehilite": { | ||
| 27 | "css_class": "highlight", | ||
| 28 | "guess_lang": False, | ||
| 29 | } | ||
| 30 | }, | ||
| 31 | ) | ||
| 32 | except Exception as e: | ||
| 33 | sys.stdout.write(f"<p>Error rendering markdown: {e}</p>") | ||
| 34 | sys.stdin.seek(0) | ||
| 35 | sys.stdout.write(f"<pre>{sys.stdin.read()}</pre>") | ||
| 36 | |||
| 37 | sys.stdout.write("</div>") | ||
diff --git a/responsive/syntax-material.py b/responsive/syntax-material.py new file mode 100755 index 0000000..3176691 --- /dev/null +++ b/responsive/syntax-material.py | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | import sys | ||
| 3 | |||
| 4 | from pygments import highlight | ||
| 5 | from pygments.formatters import HtmlFormatter | ||
| 6 | from pygments.lexers import get_lexer_for_filename, guess_lexer | ||
| 7 | from pygments.util import ClassNotFound | ||
| 8 | |||
| 9 | |||
| 10 | def main(): | ||
| 11 | filename = sys.argv[-1] if len(sys.argv) > 1 else "stdin" | ||
| 12 | |||
| 13 | try: | ||
| 14 | data = sys.stdin.read() | ||
| 15 | except Exception: | ||
| 16 | return | ||
| 17 | |||
| 18 | try: | ||
| 19 | lexer = get_lexer_for_filename(filename) | ||
| 20 | except ClassNotFound: | ||
| 21 | try: | ||
| 22 | lexer = guess_lexer(data) | ||
| 23 | except ClassNotFound: | ||
| 24 | sys.stdout.write(f"<pre>{data}</pre>") | ||
| 25 | return | ||
| 26 | |||
| 27 | formatter = HtmlFormatter(style="default", nowrap=True, classprefix="hl-") | ||
| 28 | |||
| 29 | try: | ||
| 30 | sys.stdout.write("<style>.hl- { display: inline; }</style>") | ||
| 31 | highlight(data, lexer, formatter, sys.stdout) | ||
| 32 | except BrokenPipeError: | ||
| 33 | pass | ||
| 34 | |||
| 35 | |||
| 36 | if __name__ == "__main__": | ||
| 37 | main() | ||
