From acf755fde16e11124863532c615610a130570153 Mon Sep 17 00:00:00 2001 From: ronny abraham Date: Tue, 24 Mar 2026 01:53:09 +0200 Subject: [PATCH] added templates, functions to implement templating for project-store, and seprated them out of config.el to core.el --- config.el | 218 ++------------- ronny/core.el | 263 ++++++++++++++++++ templates/notes/store/default.org | 12 + .../notes/store/product-brand-design.org | 28 ++ .../notes/store/product-brand-launch.org | 19 ++ .../notes/store/product-brand-overview.org | 31 +++ 6 files changed, 370 insertions(+), 201 deletions(-) create mode 100644 ronny/core.el create mode 100644 templates/notes/store/default.org create mode 100644 templates/notes/store/product-brand-design.org create mode 100644 templates/notes/store/product-brand-launch.org create mode 100644 templates/notes/store/product-brand-overview.org diff --git a/config.el b/config.el index 7ab0398..fbfd599 100644 --- a/config.el +++ b/config.el @@ -108,7 +108,7 @@ (setenv "PATH" (concat (getenv "JAVA_HOME") "/bin:" (getenv "PATH"))) (add-to-list 'exec-path (concat (getenv "JAVA_HOME") "/bin")) -(defun ronny/insert-ecomm-template () +(defun ronny-insert-ecomm-template () "Insert the e-commerce lesson template into the current buffer." (interactive) (insert-file-contents "~/.doom.d/templates/notes/ecomm-lesson.org") @@ -117,7 +117,7 @@ (when (re-search-forward "%(file-name-base buffer-file-name)" nil t) (replace-match (file-name-base (or buffer-file-name "Untitled")))))) -(defun ronny/insert-envy-template () +(defun ronny-insert-envy-template () "Insert the facebook envy lesson template into the current buffer." (interactive) (insert-file-contents "~/.doom.d/templates/notes/facebook_envy-lesson.org") @@ -136,7 +136,7 @@ (when (search-forward "%(lesson-code)" nil t) (replace-match lesson-code t t))))) -(defun ronny/insert-radiate-template () +(defun ronny-insert-radiate-template () "Insert the radiate lesson template into the current buffer." (interactive) (insert-file-contents "~/.doom.d/templates/notes/radiate-lesson.org") @@ -155,206 +155,22 @@ (when (search-forward "%(lesson-code)" nil t) (replace-match lesson-code t t))))) -;; commands to export properly -;; -;; html: org-export-html-to-exports -;; pdf: org-export-pdf-to-exports -;; retrieve the top level path that contains _exports -(defun ronny/exports-root () - "Find the nearest parent directory containing _exports." - (let ((root (locate-dominating-file default-directory "_exports"))) - (unless root - (error "Could not find project root containing _exports/")) - (expand-file-name root))) - -;; takes the current file and return its path relative to the project root -(defun ronny/exports-relative-path () - "Return current Org file path relative to the project root." - - ;; check whether current buffer is currently attached to a file - ;; - ;; 1a. call the exports-root function to get the _export root - ;; 1b. make sure it ends with a trailing slash - ;; - ;; 2a. get the full absolute path of the current file - ;; 2b. put it in a variable called "file" - ;; - ;; 3a. make sure that the file is located somewhere under the root path that ALSO contains "_exports" - ;; 3b strip away the root part and return the relative part - (unless buffer-file-name - (error "Buffer is not visiting a file")) - (let* ((root (file-name-as-directory (ronny/exports-root))) ;; 1a / 1b - (file (expand-file-name buffer-file-name))) ;; 2a, 2b - (unless (string-prefix-p root file) ;; 3a - (error "Current file is not under project root")) - (file-relative-name file root))) ;; 3b - -;; compute the _exports path for the file -;; -;; args: -;; format-dir -> "html" / "pdf" -;; extension -> ".html" / ".pdf" -;; -;; 1a get the project root and store it in "root" -;; 2a get the relative path and store it in "relpath" -;; 2b remove the extension from the file and store in "rel-no-ext" -;; 3a create the filepath that will exist from _exports + the relative filepath and ext -;; 3b put that under the root path -;; 4a retrieve only the directory part of the path -;; 4b make the directory if it doesn't exist -;; 5a return the final path -(defun ronny/exports-path (format-dir extension) - "Build export path under _exports/FORMAT-DIR preserving source structure." - (let* ((root (ronny/exports-root)) ;; 1a - (relpath (ronny/exports-relative-path)) ;; 2a - (rel-no-ext (file-name-sans-extension relpath)) ;; 2b - (outfile (expand-file-name - (concat "_exports/" format-dir "/" rel-no-ext extension) ;; 3a - root)) ;; 3b - (outdir (file-name-directory outfile))) ;; 4a - (make-directory outdir t) ;; 4b - outfile)) ;; 5a - -;; command to export the current Org file to HTML (run interactively) -;; -;; 1a make the function callable as an emacs command -;; - can run with M-x -;; - can bind to a key -;; 2a get the full export path for an html export -;; 3a call the export to command to generate an html file based on the current org file -;; 3b confirmation message display in minibuffer -(defun ronny/org-export-html-to-exports () - "Export current Org file to _exports/html preserving directory structure." - (interactive) ;; 1a - (let ((outfile (ronny/exports-path "html" ".html"))) ;; 2a - (org-export-to-file 'html outfile nil nil nil nil nil) ;; 3a - (message "Exported HTML to %s" outfile))) ;; 3b - -;; same as above but for latex/pdf -;; (defun ronny/org-export-pdf-to-exports () -;; "Export current Org file to _exports/pdf preserving directory structure." -;; (interactive) -;; (let ((outfile (ronny/exports-path "pdf" ".pdf"))) -;; (org-export-to-file 'latex outfile nil nil nil nil nil) -;; (message "Exported PDF to %s" outfile))) - -;; export to pdf -;; -;; generate the pdf in the normal way -;; file is created next to the org source file -;; move it to where it should be under _exports -;; -;; 1a make this funciton callable -;; -;; 2a put the final _export path as a string in "outfile" -;; 2b get the src dir and put it in srcdir -;; 2c get the src file name and put it in base -;; 2d replace the ext org with pdf and put this value in pdf-src -;; -;; 3a generate the pdf normally -;; -;; 4a use rename to move the pdf to _exports -;; -(defun ronny/org-export-pdf-to-exports () - "Export current Org file to _exports/pdf and clean up LaTeX artifacts." - (interactive) ; 1a - (let* ((outfile (ronny/exports-path "pdf" ".pdf")) ;; 2a - (srcdir (file-name-directory buffer-file-name)) ;; 2b - (base (file-name-base buffer-file-name)) ;; 2c - (pdf-src (expand-file-name (concat base ".pdf") srcdir))) ;; 2d - - ;; Export PDF next to the source Org file - (org-latex-export-to-pdf) ; 3a - - ;; Move PDF to _exports - (unless (file-exists-p pdf-src) - (error "Expected PDF not found: %s" pdf-src)) - (rename-file pdf-src outfile t) ;; 4a - - ;; Delete common LaTeX byproducts left next to the source Org file - (dolist (f (directory-files srcdir t - (concat "^" (regexp-quote base) - "\\.\\(tex\\|aux\\|log\\|out\\|toc\\|nav\\|snm\\|fls\\|fdb_latexmk\\)$"))) - (delete-file f)) - - (message "Exported PDF to %s" outfile))) - -;; exports to odt and docx -;; see above -(defun ronny/org-export-odt-to-exports () - "Export current Org file to _exports/odt." - (interactive) - (let* ((outfile (ronny/ecomm-export-path "odt" ".odt")) - (srcdir (file-name-directory buffer-file-name)) - (base (file-name-base buffer-file-name)) - (odt-src (expand-file-name (concat base ".odt") srcdir))) - - ;; export - (org-odt-export-to-odt) - - ;; move file - (unless (file-exists-p odt-src) - (error "Expected ODT not found: %s" odt-src)) - (rename-file odt-src outfile t) - - (message "Exported ODT to %s" outfile))) - -(defun ronny/org-export-docx-to-exports () - "Export current Org file to _exports/docx via ODT." - (interactive) - (let* ((odt-out (ronny/exports-path "odt" ".odt")) - (docx-out (ronny/exports-path "docx" ".docx")) - (base (file-name-base buffer-file-name))) - - ;; first export ODT - (ronny/org-export-odt-to-exports) - - ;; convert to docx - (call-process "soffice" nil 0 nil - "--headless" - "--convert-to" "docx" - "--outdir" (file-name-directory docx-out) - odt-out) - - ;; rename to correct filename if needed - (let ((generated (expand-file-name (concat base ".docx") - (file-name-directory docx-out)))) - (rename-file generated docx-out t)) - - (message "Exported DOCX to %s" docx-out))) - -;; export + open helpers - -(defun ronny/org-export-html-to-exports-and-open () - "Export current Org file to _exports/html and open it." - (interactive) - (let ((outfile (ronny/exports-path "html" ".html"))) - (ronny/org-export-html-to-exports) - (browse-url-of-file outfile))) - -;; use the osx system to open files -(defun ronny/open-file-in-macos (path) - "Open PATH in the default macOS application." - (interactive "fOpen file: ") - (call-process "open" nil 0 nil (expand-file-name path))) - -;; use osx to open -(defun ronny/org-export-pdf-to-exports-and-open () - "Export current Org file to _exports/pdf and open it." - (interactive) - (let ((outfile (ronny/exports-path "pdf" ".pdf"))) - (ronny/org-export-pdf-to-exports) - (ronny/open-file-in-macos outfile))) - -;; Doom keybindings under SPC m e +;; --- ronny core --- +(load! "ronny/core") +;; Doom keybindings under SPC m C (map! :map org-mode-map :leader (:prefix ("m C" . "custom export") - :desc "Export HTML" "h" #'ronny/org-export-html-to-exports - :desc "Export PDF" "p" #'ronny/org-export-pdf-to-exports - :desc "Export HTML open" "o" #'ronny/org-export-html-to-exports-and-open - :desc "Export PDF open" "P" #'ronny/org-export-pdf-to-exports-and-open - :desc "ODT export" "d" #'ronny/org-export-odt-to-exports - :desc "DOCX export" "D" #'ronny/org-export-docx-to-exports)) + :desc "Export HTML" "h" #'ronny-org-export-html-to-exports + :desc "Export PDF" "p" #'ronny-org-export-pdf-to-exports + :desc "Export HTML open" "o" #'ronny-org-export-html-to-exports-and-open + :desc "Export PDF open" "P" #'ronny-org-export-pdf-to-exports-and-open + :desc "ODT export" "d" #'ronny-org-export-odt-to-exports + :desc "DOCX export" "D" #'ronny-org-export-docx-to-exports)) + +(map! :map org-mode-map + :leader + (:prefix ("m C t" . "template") + :desc "Insert online store template" "o" #'ronny-template-insert-online-store)) diff --git a/ronny/core.el b/ronny/core.el new file mode 100644 index 0000000..4fe1d27 --- /dev/null +++ b/ronny/core.el @@ -0,0 +1,263 @@ +;;; ronny/core.el --- Core reusable functions -*- lexical-binding: t; -*- + +;; commands to export properly +;; +;; html: org-export-html-to-exports +;; pdf: org-export-pdf-to-exports + +;; retrieve the top level path that contains _exports +(defun ronny-path-exports-root () + "Find the nearest parent directory containing _exports." + (let ((root (locate-dominating-file default-directory "_exports"))) + (unless root + (error "Could not find project root containing _exports/")) + (expand-file-name root))) + +(defun ronny-path-depth-from-root () + "Return how many directory levels current file is below project root." + (unless buffer-file-name + (error "Buffer is not visiting a file")) + (let* ((root (file-name-as-directory (ronny-path-exports-root))) + (file-dir (file-name-directory (expand-file-name buffer-file-name))) + (rel-dir (directory-file-name (file-relative-name file-dir root)))) + (if (string-empty-p rel-dir) + 0 + (length (split-string rel-dir "/" t))))) + +;; takes the current file and return its path relative to the project root +(defun ronny-path-exports-relative-path () + "Return current Org file path relative to the project root." + + ;; check whether current buffer is currently attached to a file + ;; + ;; 1a. call the path-exports-root function to get the _export root + ;; 1b. make sure it ends with a trailing slash + ;; + ;; 2a. get the full absolute path of the current file + ;; 2b. put it in a variable called "file" + ;; + ;; 3a. make sure that the file is located somewhere under the root path that ALSO contains "_exports" + ;; 3b strip away the root part and return the relative part + (unless buffer-file-name + (error "Buffer is not visiting a file")) + (let* ((root (file-name-as-directory (ronny-path-exports-root))) ;; 1a / 1b + (file (expand-file-name buffer-file-name))) ;; 2a, 2b + (unless (string-prefix-p root file) ;; 3a + (error "Current file is not under project root")) + (file-relative-name file root))) ;; 3b + +;; compute the _exports path for the file +;; +;; args: +;; format-dir -> "html" / "pdf" +;; extension -> ".html" / ".pdf" +;; +;; 1a get the project root and store it in "root" +;; 2a get the relative path and store it in "relpath" +;; 2b remove the extension from the file and store in "rel-no-ext" +;; 3a create the filepath that will exist from _exports + the relative filepath and ext +;; 3b put that under the root path +;; 4a retrieve only the directory part of the path +;; 4b make the directory if it doesn't exist +;; 5a return the final path +(defun ronny-exports-build-path (format-dir extension) + "Build export path under _exports/FORMAT-DIR preserving source structure." + (let* ((root (ronny-path-exports-root)) ;; 1a + (relpath (ronny-path-exports-relative-path)) ;; 2a + (rel-no-ext (file-name-sans-extension relpath)) ;; 2b + (outfile (expand-file-name + (concat "_exports/" format-dir "/" rel-no-ext extension) ;; 3a + root)) ;; 3b + (outdir (file-name-directory outfile))) ;; 4a + (make-directory outdir t) ;; 4b + outfile)) ;; 5a + +(defun ronny-util-repeat-string (s n) + "Repeat string S, N times." + (apply #'concat (make-list n s))) + +(defun ronny-title-from-file-name () + "Convert file name to title. +Example: product_strategy.org → Product Strategy" + (unless buffer-file-name + (error "Buffer is not visiting a file")) + (let* ((base (file-name-base buffer-file-name)) + (spaced (replace-regexp-in-string "[-_]+" " " base))) + (string-join + (mapcar #'capitalize (split-string spaced " +" t)) + " "))) + +(defun ronny-title-from-parent-folder () + "Return parent directory name as title." + (unless buffer-file-name + (error "Buffer is not visiting a file")) + (let* ((parent (file-name-nondirectory + (directory-file-name + (file-name-directory (expand-file-name buffer-file-name)))))) + (string-join + (mapcar #'capitalize + (split-string (replace-regexp-in-string "[-_]+" " " parent) " +" t)) + " "))) + +(defun ronny-template-read-file (name) + "Read template NAME from ~/.doom.d/templates/notes/." + (let ((path (expand-file-name name "~/.doom.d/templates/notes/"))) + (unless (file-exists-p path) + (error "Template not found: %s" path)) + (with-temp-buffer + (insert-file-contents path) + (buffer-string)))) + +(defun ronny-template-fill (template replacements) + "Replace placeholders in TEMPLATE using REPLACEMENTS." + (dolist (pair replacements template) + (setq template + (replace-regexp-in-string + (regexp-quote (format "{{%s}}" (car pair))) + (cdr pair) + template t t)))) + +(defun ronny-template-insert-online-store () + "Insert online store Org template based on current file path." + (interactive) + (let* ((template (ronny-template-read-file "store/default.org")) + (depth (ronny-util-repeat-string "../" (ronny-path-depth-from-root))) + (filled + (ronny-template-fill + template + `(("title" . ,(ronny-title-from-file-name)) + ("media_prefix" . ,depth) + ("toc_prefix" . ,depth) + ("parent_title" . ,(ronny-title-from-parent-folder)))))) + (insert filled))) + +;; command to export the current Org file to HTML (run interactively) +;; +;; 1a make the function callable as an emacs command +;; - can run with M-x +;; - can bind to a key +;; 2a get the full export path for an html export +;; 3a call the export to command to generate an html file based on the current org file +;; 3b confirmation message display in minibuffer +(defun ronny-org-export-html-to-exports () + "Export current Org file to _exports/html preserving directory structure." + (interactive) ;; 1a + (let ((outfile (ronny-exports-build-path "html" ".html"))) ;; 2a + (org-export-to-file 'html outfile nil nil nil nil nil) ;; 3a + (message "Exported HTML to %s" outfile))) ;; 3b + +;; same as above but for latex/pdf +;; (defun ronny-org-export-pdf-to-exports () +;; "Export current Org file to _exports/pdf preserving directory structure." +;; (interactive) +;; (let ((outfile (ronny-exports-build-path "pdf" ".pdf"))) +;; (org-export-to-file 'latex outfile nil nil nil nil nil) +;; (message "Exported PDF to %s" outfile))) + +;; export to pdf +;; +;; generate the pdf in the normal way +;; file is created next to the org source file +;; move it to where it should be under _exports +;; +;; 1a make this funciton callable +;; +;; 2a put the final _export path as a string in "outfile" +;; 2b get the src dir and put it in srcdir +;; 2c get the src file name and put it in base +;; 2d replace the ext org with pdf and put this value in pdf-src +;; +;; 3a generate the pdf normally +;; +;; 4a use rename to move the pdf to _exports +;; +(defun ronny-org-export-pdf-to-exports () + "Export current Org file to _exports/pdf and clean up LaTeX artifacts." + (interactive) ; 1a + (let* ((outfile (ronny-exports-build-path "pdf" ".pdf")) ;; 2a + (srcdir (file-name-directory buffer-file-name)) ;; 2b + (base (file-name-base buffer-file-name)) ;; 2c + (pdf-src (expand-file-name (concat base ".pdf") srcdir))) ;; 2d + + ;; Export PDF next to the source Org file + (org-latex-export-to-pdf) ; 3a + + ;; Move PDF to _exports + (unless (file-exists-p pdf-src) + (error "Expected PDF not found: %s" pdf-src)) + (rename-file pdf-src outfile t) ;; 4a + + ;; Delete common LaTeX byproducts left next to the source Org file + (dolist (f (directory-files srcdir t + (concat "^" (regexp-quote base) + "\\.\\(tex\\|aux\\|log\\|out\\|toc\\|nav\\|snm\\|fls\\|fdb_latexmk\\)$"))) + (delete-file f)) + + (message "Exported PDF to %s" outfile))) + +;; exports to odt and docx +;; see above +(defun ronny-org-export-odt-to-exports () + "Export current Org file to _exports/odt." + (interactive) + (let* ((outfile (ronny-exports-build-path "odt" ".odt")) + (srcdir (file-name-directory buffer-file-name)) + (base (file-name-base buffer-file-name)) + (odt-src (expand-file-name (concat base ".odt") srcdir))) + + ;; export + (org-odt-export-to-odt) + + ;; move file + (unless (file-exists-p odt-src) + (error "Expected ODT not found: %s" odt-src)) + (rename-file odt-src outfile t) + + (message "Exported ODT to %s" outfile))) + +(defun ronny-org-export-docx-to-exports () + "Export current Org file to _exports/docx via ODT." + (interactive) + (let* ((odt-out (ronny-exports-build-path "odt" ".odt")) + (docx-out (ronny-exports-build-path "docx" ".docx")) + (base (file-name-base buffer-file-name))) + + ;; first export ODT + (ronny-org-export-odt-to-exports) + + ;; convert to docx + (call-process "soffice" nil 0 nil + "--headless" + "--convert-to" "docx" + "--outdir" (file-name-directory docx-out) + odt-out) + + ;; rename to correct filename if needed + (let ((generated (expand-file-name (concat base ".docx") + (file-name-directory docx-out)))) + (rename-file generated docx-out t)) + + (message "Exported DOCX to %s" docx-out))) + +;; export + open helpers + +;; use the osx system to open files +(defun ronny-open-file-in-macos (path) + "Open PATH in the default macOS application." + (interactive "fOpen file: ") + (call-process "open" nil 0 nil (expand-file-name path))) + +(defun ronny-org-export-html-to-exports-and-open () + "Export current Org file to _exports/html and open it." + (interactive) + (let ((outfile (ronny-exports-build-path "html" ".html"))) + (ronny-org-export-html-to-exports) + (ronny-open-file-in-macos outfile))) + +;; use osx to open +(defun ronny-org-export-pdf-to-exports-and-open () + "Export current Org file to _exports/pdf and open it." + (interactive) + (let ((outfile (ronny-exports-build-path "pdf" ".pdf"))) + (ronny-org-export-pdf-to-exports) + (ronny-open-file-in-macos outfile))) diff --git a/templates/notes/store/default.org b/templates/notes/store/default.org new file mode 100644 index 0000000..000b221 --- /dev/null +++ b/templates/notes/store/default.org @@ -0,0 +1,12 @@ +#+title: {{title}} +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+OPTIONS: H:6 + +* Navigation +- [[{{toc_prefix}}_toc.org][Top TOC]] +- [[./_toc.org][{{parent_title}} TOC]] + +* Content diff --git a/templates/notes/store/product-brand-design.org b/templates/notes/store/product-brand-design.org new file mode 100644 index 0000000..0d5fd8f --- /dev/null +++ b/templates/notes/store/product-brand-design.org @@ -0,0 +1,28 @@ +#+title: Design: {{title}} +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+OPTIONS: H:6 + +* Navigation +- [[{{toc_prefix}}_toc.org][Top TOC]] +- [[{{brand_toc_prefix}}_toc.org][{{brand_title}} TOC]] + +* Content +** Concept +Short description of the design idea. + +** Visual Notes +Pose, mood, composition, major elements. + +** Product Suitability +- phone case safe? +- top-left safe? +- pattern vs focal composition? + +** Asset Location +Path to source files in ~/Pictures/designs/ecomm/samuraicat/... + +** Status +idea / in progress / ready / launched diff --git a/templates/notes/store/product-brand-launch.org b/templates/notes/store/product-brand-launch.org new file mode 100644 index 0000000..f88c52a --- /dev/null +++ b/templates/notes/store/product-brand-launch.org @@ -0,0 +1,19 @@ +#+title: {{brand_name}} Launch {{launch_no}} +#+title:/ +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+OPTIONS: H:6 + +* Navigation +- [[{{toc_prefix}}_toc.org][Top TOC]] +- [[../../_toc.org][Products TOC]] +- [[../_toc.org][{{brand_name}} TOC]] + +* Content +** Batch +** Designs +** Launch Date +** 2 Week Check +** 4 Week Decision diff --git a/templates/notes/store/product-brand-overview.org b/templates/notes/store/product-brand-overview.org new file mode 100644 index 0000000..16690a7 --- /dev/null +++ b/templates/notes/store/product-brand-overview.org @@ -0,0 +1,31 @@ +#+title: Brand Overview: {{brand_title}} +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+OPTIONS: H:6 + +* Navigation +- [[{{toc_prefix}}_toc.org][Top TOC]] +- [[../_toc.org][Products TOC]] + +* Content +** Concept +What Samurai Cat is. + +** Style +Visual tone, themes, recurring motifs. + +*** brand-wide tendencies +*** style families + +** Audience +Who it is for. +*** Primary: +*** Secondary: + +** Fits +What kinds of designs belong here. + +** Does Not Fit +What should be excluded.