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.