View file PF.Src/Core/Flavor/Flavor.php

File size: 22.05Kb
<?php

namespace Core\Flavor;

class Object {
	public $id;
	public $name;
	public $vars;
	public $path;
	public $url;
	public $icon = '';
	public $legacy = ['theme' => 'bootstrap', 'flavor' => 'bootstrap'];
	public $blocks = [];
	public $store_id;
	public $version;

	public function __construct($path) {
		$this->path = $path;
		$this->url = str_replace([PHPFOX_DIR_SITE, PHPFOX_DS], [\Phpfox::getLib('cdn')->getUrl(setting('core.path_actual')) . 'PF.Site/', '/'], $this->path);
		if (file_exists($this->path . 'theme.png')) {
			$this->icon = $this->url . 'theme.png?v=' . uniqid();
		}
		$this->legacy = (object) $this->legacy;
		$this->blocks = (object) $this->blocks;

		$json = json_decode(file_get_contents($path . 'theme.json'));
		foreach ($json as $key => $value) {
			$this->{$key} = $value;
		}
	}

	public function save($type, $values, $sub_type = '') {
		$dir = $this->path;
		switch ($type) {
			case 'settings':
				$file = $this->path . 'theme.json';
				file_put_contents($file, $values);
				break;
			case 'icon':
				$file = $this->path . 'theme.png';
				$url = $this->url . 'theme.png';

				move_uploaded_file($values['tmp_name'], $file);

				return $url;

				break;
			case 'content':
				storage()->del('flavor/content/' . $this->id);
				storage()->set('flavor/content/' . $this->id, $values);

				break;
			case 'html':
				$path = $this->path . 'html/layout.html';

				file_put_contents($path, $values);

				break;
			case 'js':
				$path = $this->path . 'assets/autoload.js';

				file_put_contents($path, $values);

				break;
			case 'banners':
                $dir = $this->path . 'assets' . PHPFOX_DS . 'banners' . PHPFOX_DS;
				if (!is_dir($dir)) {
					mkdir($dir);
				}
				$hash = $values['name'];

				move_uploaded_file($values['tmp_name'], $dir . $hash);

				return str_replace(PHPFOX_DS, '/', str_replace(PHPFOX_DIR_SITE, home() . 'PF.Site/', $dir . $hash));

				break;
			case 'logos':
                $dir = $dir . 'assets' . PHPFOX_DS . $sub_type . PHPFOX_DS;
				if (!is_dir($dir)) {
					mkdir($dir);
				}
				$ext = \Phpfox_File::instance()->getFileExt($values['name']);
				$hash = md5(uniqid()) . '.' . $ext;
				$id = 'flavor/' . $sub_type . '/' . $this->id;

				move_uploaded_file($values['tmp_name'], $dir . $hash);

				storage()->del($id);
				storage()->set($id, $hash);

				break;

			case 'default_photo':
				$dir = $dir . 'assets' . PHPFOX_DS . 'defaults' . PHPFOX_DS;
				if (!is_dir($dir)) {
					mkdir($dir);
				}
				$ext = \Phpfox_File::instance()->getFileExt($values['name']);
				$name = $sub_type . '.' . $ext;
				$id = 'flavor/defaults/' . $this->id;

				$data = (storage()->get($id)) ? json_decode(json_encode(storage()->get($id)->value), true) : [];
				if (isset($data[$sub_type]) && file_exists($dir . $data[$sub_type])) {
					unlink($dir . $data[$sub_type]);
				}
				$data[$sub_type] = $name;

				move_uploaded_file($values['tmp_name'], $dir . $name);

				storage()->del($id);
				storage()->set($id, $data);

				break;

			case 'remove_default':
				$dir = $dir . 'assets' . PHPFOX_DS . 'defaults' . PHPFOX_DS;
				$id = 'flavor/defaults/' . $this->id;

				$data = (storage()->get($id)) ? json_decode(json_encode(storage()->get($id)->value), true) : [];
				if (isset($data[$sub_type]) && file_exists($dir . $data[$sub_type])) {
					unlink($dir . $data[$sub_type]);
					unset($data[$sub_type]);
				}
				storage()->del($id);
				storage()->set($id, $data);
				break;

			case 'css':
				$less_file = $this->path . 'assets/autoload.less';
				$css_file = $this->path . 'assets/autoload.css';

				file_put_contents($less_file, $values);

				$lessc = new \lessc();
				$lessc->addImportDir($this->path . 'assets/');
				$lessc->compileFile($less_file, $css_file);

				break;
			case 'design':
				$less = '';
				$theme_suffix = request()->get('theme_suffix');
				$theme_suffix_file = null;
				$less_file = $this->path . 'assets'.PHPFOX_DS.'variables.less';

				if($theme_suffix){
					$theme_suffix_file =$this->path . 'assets'.PHPFOX_DS.'variables'.$theme_suffix.'.less';
					if(!file_exists($theme_suffix_file)){
						$theme_suffix_file = null;
					}
				}

				if($theme_suffix_file)
					$less_file =  $theme_suffix_file;

				if (!file_exists($less_file)) {
					$lines = '';
					foreach ($this->vars as $var => $value) {
						$lines .= "@{$var}:{$value->value};\n";
					}
					file_put_contents($less_file, $lines);
				}



				$less_input = $this->path . 'assets/autoload.less';
				$css_output = $this->path . 'assets/autoload.css';
				if (!file_exists($less_input)) {
					file_put_contents($less_input, "\n@import \"variables\";\n" . file_get_contents($css_output));
				}

				$lines = file($less_file);
				foreach ($lines as $line) {
					$line = trim($line);
					if (empty($line)) {
						continue;
					}

					if (substr($line, 0, 1) == '@') {
						$parts = array_map('trim', explode(':', $line));
						$var = str_replace('@', '', $parts[0]);
						if (!isset($parts[1])) {
							continue;
						}
						$value = trim(explode(';', $parts[1])[0]);

						if (isset($values[$var])) {
							$value = $values[$var];
						}

						$less .= "@{$var}: {$value};\n";
					}
				}

				file_put_contents($less_file, $less);

				if($theme_suffix_file){
					$less_file = $this->path . 'assets'.PHPFOX_DS.'variables.less';
					file_put_contents($less_file, $less);
				}

				$lessc = new \lessc();
				$lessc->addImportDir($this->path . 'assets/');

				try {
					$lessc->compileFile($less_input, $css_output);
				} catch (\Exception $e) {
					if (PHPFOX_DEBUG) {
						\Phpfox_Error::trigger($e->getMessage(), E_USER_ERROR);
					}
				}



				break;
		}

		return true;
	}

	public function html($exist = false) {
		return file_get_contents($this->html_path($exist));
	}

	public function html_path($exist = false) {
		$file = $this->path . 'html/layout.html';
		if (!file_exists($file)) {
			if ($exist) {
				$o = $file;
			}

			$file = str_replace($this->id . '/html/', 'bootstrap/html/', $file);

			if ($exist) {
				if (!is_dir($this->path . 'html/')) {
					mkdir($this->path . 'html/');
				}
				copy($file, $o);
				$file = $o;
			}
		}

		return $file;
	}

	public function css() {
		$file = $this->path . 'assets/autoload.less';
		if (!file_exists($file)) {
			$file = $this->path . 'assets/autoload.css';
		}

		return file_get_contents($file);
	}

	public function json() {
		$file = $this->path . 'theme.json';

		return file_get_contents($file);
	}

	public function has_js() {
		return (file_exists($this->path . 'assets/autoload.js') ? true : false);
	}

	public function js() {
		$file = $this->path . 'assets/autoload.js';

		return file_get_contents($file);
	}

	public function logo_url($type = 'logos') {
		$logo = $this->logo($type);
		if (!$logo) {
			return '';
		}

		$logo = str_replace(PHPFOX_DIR_SITE, setting('core.path_actual') . 'PF.Site/', $logo);
        //This is url, if on window, We have to fix the link
        $logo = str_replace(PHPFOX_DS, '/', $logo);
		if (request()->get('force-flavor')) {
			$logo = $logo . '?v=' . uniqid();
		}
		return $logo;
	}

	public function logo($type = 'logos') {
		$id = 'flavor/' . $type . '/' . $this->id;
		$dir = $this->path . 'assets' . PHPFOX_DS . $type . PHPFOX_DS;
		if (!is_dir($dir)) {
			mkdir($dir, 0777, true);
		}
		$logo = storage()->get($id);
		if (isset($logo->value)) {
			$file = $dir . $logo->value;
			if (file_exists($file)) {
				return $file;
			}
		}

		return null;
	}

	public function default_photo($type = null, $bUrl = false) {
		if (!$type) return false;
		$id = 'flavor/defaults/' . $this->id;
		$dir = $this->path . 'assets' . PHPFOX_DS . 'defaults' . PHPFOX_DS;
		if (!is_dir($dir)) {
			mkdir($dir);
		}
		$photos = storage()->get($id);
		$return = null;
		if (isset($photos->value) && is_array($defaults =  json_decode(json_encode($photos->value), true)) && isset($defaults[$type])) {
			$file = $dir . $defaults[$type];
			if (file_exists($file)) {
				$return = $file;
			}
		}

		if ($bUrl && $return) {
			$return = str_replace(PHPFOX_DIR_SITE, \Phpfox::getLib('cdn')->getUrl(setting('core.path_actual')) . 'PF.Site/', $return);
			$return = str_replace(PHPFOX_DS, '/', $return);
			if (request()->get('force-flavor')) {
				$return = $return . '?v=' . uniqid();
			}
		}
		return $return;
	}

	public function favicon() {
		return $this->logo('favicons');
	}

	public function favicon_url() {
		return $this->logo_url('favicons');
	}

	public function banners() {
		$banners = [];
        $dir = $this->path . 'assets' . PHPFOX_DS . 'banners' . PHPFOX_DS;
		if (!is_dir($dir)) {
			mkdir($dir);
		}
		foreach (scandir($dir) as $file) {
			if (preg_match('/^(.*)\.([jpg|png|gif|jpeg]+)$/i', $file)) {
				$banners[] = str_replace(PHPFOX_DS, '/', str_replace(PHPFOX_DIR_SITE, home() . 'PF.Site/', $dir . $file));
			}
		}

		return $banners;
	}

	public function content() {
		$content = storage()->get('flavor/content/' . $this->id);
		if (isset($content->value)) {
			return $content->value;
		}

		return '';
	}

	public function export() {
		$dir = $this->path;
		$iter = new \RecursiveIteratorIterator(
			new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
			\RecursiveIteratorIterator::SELF_FIRST,
			\RecursiveIteratorIterator::CATCH_GET_CHILD
		);
		$zip_file = PHPFOX_DIR_FILE . 'static'.PHPFOX_DS.'theme-' . $this->id . '.zip';
		$Zip = new \ZipArchive();
		$Zip->open($zip_file, \ZipArchive::CREATE);

		$paths = [];
		foreach ($iter as $path => $dir) {
			if ($dir instanceof \SplFileInfo) {
				if ($dir->isFile() && strpos($path, $this->path . 'flavor') === false && basename($dir) != '.DS_Store') {
					if (preg_match('/^(.*)\.(json)$/i', $path)) {
						$content = file_get_contents($path);
						$paths[str_replace($this->path, '', $path)] = $content;
					}
					else {
						$paths['files_path'][] = str_replace($this->path, '', $path);
						$Zip->addFile($dir->getPathName(), str_replace($this->path, '', $path));
					}
				}
				elseif ($dir->isDir() && strpos($path, $this->path . 'flavor') === false) {
					$Zip->addEmptyDir(str_replace($this->path, '', $path));
				}
			}
		}
		$paths = json_encode($paths, JSON_PRETTY_PRINT);

		$json_file = PHPFOX_DIR_FILE . 'static'.PHPFOX_DS.'theme-' . $this->id . '.json';

		file_put_contents($json_file, $paths);

		$Zip->addFile($json_file, 'theme-' . $this->id . '.json');
		$Zip->close();

		unlink($json_file);

		\Phpfox_File::instance()->forceDownload($zip_file, 'phpfox-theme-' . $this->id . '.zip');
	}

	public function revert() {
		$dir = $this->path;
		$bootstrap = json_decode(file_get_contents(PHPFOX_DIR_SITE . '/Apps/core-flavors/flavors/bootstrap.json'));
		foreach ($bootstrap as $file => $content) {
			if (preg_match('/^(.*)\.(gif|jpg|jpeg|png)$/i', $file)) {
				$content = base64_decode($content);
			}

			file_put_contents($dir . ltrim($file, '/'), $content);
		}

		$json = json_decode(file_get_contents($dir . 'theme.json'));
		$json->id = strtolower($this->id);
		$json->name = $this->name;
		file_put_contents($dir . 'theme.json', json_encode($json, JSON_PRETTY_PRINT));

		return true;
	}

	public function delete() {
		$dirs = [];
		$iter = new \RecursiveIteratorIterator(
			new \RecursiveDirectoryIterator($this->path, \RecursiveDirectoryIterator::SKIP_DOTS),
			\RecursiveIteratorIterator::CHILD_FIRST,
			\RecursiveIteratorIterator::CATCH_GET_CHILD
		);
		foreach ($iter as $path => $dir) {
			if ($dir instanceof \SplFileInfo && $dir->isDir()) {
				$dirs[] = $path;
			}
		}

		$files = \Phpfox_File::instance()->getAllFiles($this->path, true);
		foreach ($files as $file) {
			unlink($file);
		}

		foreach ($dirs as $dir) {
			rmdir($dir);
		}

		rmdir($this->path);

		$id = 'flavor' . PHPFOX_DS . 'defaults' . PHPFOX_DS . $this->id;
		storage()->del($id);

		return true;
	}

	public function has_less() {
		return (file_exists($this->path . 'assets/variables.less') ? true : false);
	}

	public function design() {
		$theme_suffix =  !empty($_REQUEST['theme_suffix'])?$_REQUEST['theme_suffix']: null;
		$less_input = $this->path . 'assets' . PHPFOX_DS . 'variables.less';
		if($theme_suffix){
			$temp = $this->path . 'assets'. PHPFOX_DS . 'variables'.$theme_suffix.'.less';
			if(file_exists($temp)){
				$less_input =  $temp;
			}
		}

		$get_vars = function($less_input) {
			$variables = [];

			$lines = file($less_input);
			foreach ($lines as $line) {
				$line = trim($line);
				if (empty($line)) {
					continue;
				}

				if (substr($line, 0, 1) == '@') {
					$parts = array_map('trim', explode(':', $line));
					$var = str_replace('@', '', $parts[0]);
					if (!isset($parts[1])) {
						continue;
					}
					$value = trim(explode(';', $parts[1])[0]);
					$variables[$var] = $value;
				}
			}

			return $variables;
		};

		$variables = array_merge($get_vars(PHPFOX_DIR_SITE . 'flavors/bootstrap/assets/variables.less'), $get_vars($less_input));


		if (is_string($this->vars) && substr($this->vars, 0, 1) == '@') {
			$bootstrap = json_decode(file_get_contents(PHPFOX_DIR_SITE . 'flavors/bootstrap/theme.json'));

			$this->vars = $bootstrap->vars;
		}

		$html = '';
		if (isset($this->vars) && count((array) $this->vars)) {
			$html .= '<form class="ajax_post" method="post" action="' . url()->make('/flavors/manage', ['id' => $this->id, 'type' => 'design','theme_suffix'=>request()->get('theme_suffix')]) . '">';

			foreach ($this->vars as $key => $value) {
				$html .= '<div class="fm_setting">';
				$html .= '<div class="fm_title">' . $value->title . '</div>';

				if (!isset($value->type)) {
					$value->type = 'text';
				}

				if (in_array($value->attr, ['max-width', 'width', 'min-width'])) {
					$value->type = 'size';
				}

				$rules = json_encode(['rule' => $value->id . '{' . $value->attr . ':[VALUE] !important;}']);
				if (isset($variables[$key])) {
					$value->value = $variables[$key];
				}

				if (!isset($value->value)) {
					$value->value = '';
				}

				switch ($value->type) {
					case "theme":
						$html .= '<div autocomplete="off" type="text" name="var[' . $key . ']" value="' . $value->value . '" data-rules=\'' . $rules . '\' >';
						foreach($value->options as $option){
							$html .= strtr('<div><a class="edit_for_theme" href="#" data-url=":url" value=":key" label=":label" :selected>:label</a></div>',[
								':key'=>$option->value,
								':label'=>$option->label,
								':selected'=> ($value->value == $option->value)? 'selected': ' ',
								':url'=>url('/flavors/manage', ['id'=>$this->id, 'type'=> 'design','theme_suffix'=> $option->value]),
							]);
						}
						$html .= '</div>';
						break;
					case 'size':
						$html .= '<input autocomplete="off" type="text" name="var[' . $key . ']" value="' . $value->value . '" data-rules=\'' . $rules . '\'>';
						break;
					default:
						$html .= '<input class="_colorpicker" data-old="' . $value->value . '" autocomplete="off" type="text" name="var[' . $key . ']" value="' . $value->value . '" data-rules=\'' . $rules . '\'>';
						$html .= '<div class="_colorpicker_holder"></div>';
						break;
				}

				$html .= '</div>';
			}
			$html .= '<div class="fm_submit"><span>Publish</span></div>';
			$html .= '</form>';
		}

		return $html;
	}
}

class Flavor {
	/**
	 * @var Object
	 */
	public $active;

	private static $_active = null;

	public function __construct() {
		if (self::$_active === null) {
			if (!is_dir(PHPFOX_DIR_SITE . 'flavors/')) {
				mkdir(PHPFOX_DIR_SITE . 'flavors/');
			}
			$default_dir = PHPFOX_DIR_SITE . 'flavors/bootstrap/';
			if (!is_dir($default_dir)) {
				$this->make([
					'name' => 'bootstrap'
				]);
			}

			$flavor = 'bootstrap';
			$default = storage()->get('flavor/default');
			if (isset($default->value)) {
				$flavor = $default->value;
			}

			$cookie = \Phpfox::getCookie('flavors_id');
			if ($cookie) {
				$flavor = $cookie;
			}

			self::$_active = $this->get($flavor);
			if (self::$_active === false) {
				self::$_active = $this->get('bootstrap');
			}
		}

		$this->active = self::$_active;
	}

	public function set_active($flavor) {
		self::$_active = $this->get($flavor);
		$this->active = self::$_active;
	}

	public function make($val, $file = null, $force_upgrade = false) {

		if ($file !== null) {
			$path = PHPFOX_DIR_FILE . 'static' . PHPFOX_DS . uniqid() . '/';
			$zip_file = $path . 'theme.zip';
			$json = null;

			mkdir($path);
			if (isset($file['is_local'])) {
				copy($file['tmp_name'], $zip_file);
			}
			else {
				move_uploaded_file($file['tmp_name'], $zip_file);
			}

			$zip = new \ZipArchive();
			$zip->open($zip_file);
			$zip->extractTo($path);
			$zip->close();

			foreach (scandir($path) as $file) {
				if (substr($file, -5) == '.json') {
					$json = json_decode(file_get_contents($path . $file), true);
					break;
				}
			}

			if ($json === null) {
				error('JSON file missing for this theme.');
			}

			$j = json_decode($json['theme.json']);

			$val['name'] = $j->id;
		}

		if (empty($val['name'])) {
			error(_p('Provide a name for your theme.'));
		}

		$name = $val['name'];
        $val['name'] = strtolower($val['name']);
		if (!preg_match('/^[^\W_]+$/', $name)) {
			error(_p('Alphanumeric characters only for the theme name.'));
		}

		$dir = PHPFOX_DIR_SITE . 'flavors/' . strtolower($name) . '/';
		if ($force_upgrade === true && is_dir($dir)) {
			\Phpfox_File::instance()->delete_directory($dir);
		}

		if (is_dir($dir)) {
			error(_p('Theme already exists.'));
		}

		mkdir($dir);
		mkdir($dir . 'assets/');
		mkdir($dir . 'html/');
		mkdir($dir . 'flavor/');

		if (isset($val['clone'])) {

			if ($val['clone'] == '__blank') {

				file_put_contents($dir . 'assets/autoload.css', '');

				$bootstrap = json_decode(file_get_contents(PHPFOX_DIR_SITE . '/Apps/core-flavors/flavors/bootstrap.json'), true);
				file_put_contents($dir . 'html/layout.html', $bootstrap['/html/layout.html']);
				file_put_contents($dir . 'theme.json', json_encode(['id' => '', 'name' => ''], JSON_PRETTY_PRINT));

			} else {
				$files = [];
				$object = $this->get($val['clone']);
				$dirs = new \RecursiveIteratorIterator(
					new \RecursiveDirectoryIterator($object->path, \RecursiveDirectoryIterator::SKIP_DOTS),
					\RecursiveIteratorIterator::SELF_FIRST,
					\RecursiveIteratorIterator::CATCH_GET_CHILD
				);
				foreach ($dirs as $file_name => $o) {
					if ($o instanceof \SplFileInfo) {
						if ($o->isDir()) {
							$file_name = str_replace('flavors/' . $val['clone'] . '/', 'flavors/' . $val['name'] . '/', $file_name);
							\Phpfox_File::instance()->mkdir($file_name, true);
						} else {
							$new_path = str_replace('flavors/' . $val['clone'] . '/', 'flavors/' . $val['name'] . '/', $file_name);
							$files[$file_name] = $new_path;
						}
					}
				}

				foreach ($files as $copy => $file) {
					copy($copy, $file);
				}
			}

		} else {
			if (isset($json)) {

				$dirs = [];
				foreach ($json as $file => $content) {
					$parts = explode('/', $file);
					unset($parts[count($parts) - 1]);
					$this_dir = implode('/', $parts);
					if (empty($this_dir)) {
						continue;
					}
					$dirs[$this_dir . '/'] = $this_dir . '/';
				}

				foreach ($dirs as $new_dir) {
					$this_dir = $dir . $new_dir;
					if (!is_dir($this_dir)) {
						\Phpfox_File::instance()->mkdir($this_dir, true);
					}
				}

				foreach ($json as $file => $content) {
					if ($file == 'files_path') {
						foreach ($content as $sPath) {
							$to_filename = $dir . $sPath;

							if (!is_dir($sDir = dirname($to_filename))) {
								mkdir($sDir, 0777, 1);
								chmod($sDir, 0777);
							}
							if (!@copy($path . $sPath, $to_filename)) {
								throw new \RuntimeException(sprintf('Can not copy from "%s" to "%s"', $path . $sPath, $to_filename));
							}
						}
					}
					else {
						if (preg_match('/^(.*)\.(gif|jpg|jpeg|png)$/i', $file)) {
							$content = base64_decode($content);
						}

						file_put_contents($dir . $file, $content);
					}
				}

			} else {
				$bootstrap = json_decode(file_get_contents(PHPFOX_DIR_SITE . '/Apps/core-flavors/flavors/bootstrap.json'));
				foreach ($bootstrap as $file => $content) {
					if (preg_match('/^(.*)\.(gif|jpg|jpeg|png)$/i', $file)) {
						$content = base64_decode($content);
					}

					file_put_contents($dir . ltrim($file, '/'), $content);
				}
			}
		}

		$json = json_decode(file_get_contents($dir . 'theme.json'));
		$json->id = strtolower($name);
		$json->name = $name;
		file_put_contents($dir . 'theme.json', json_encode($json, JSON_PRETTY_PRINT));

		//build default photos
		flavor()->build_default_photos(strtolower($name));

		return $this->get(strtolower($name));
	}

	public function get($flavor) {
		$dir = PHPFOX_DIR_SITE . 'flavors' . PHPFOX_DS;
		$path = $dir . $flavor . PHPFOX_DS;

		if (file_exists($path . 'theme.json')) {
			return new Object($path);
		}

		return false;
	}

	/**
	 * @return \Flavor\Object[]
	 */
	public function all() {
		$dir = PHPFOX_DIR_SITE . 'flavors';
		if (!is_dir($dir)) {
			error('Flavor folder does not exist.');
		}

		$flavors = [];
		foreach (scandir($dir) as $flavor) {
			if (($flavor = $this->get($flavor))) {
				$flavors[] = $flavor;
			}
		}

		return $flavors;
	}

	public function rebuild_bootstrap($less = false) {
		$theme = new \Core\Theme('bootstrap');
		$theme->get()->delete();

		$theme = new \Core\Theme();
		$new_theme = $theme->make(['name' => 'Bootstrap'], null, false, 'bootstrap');
		db()->update(':theme', ['is_default' => 1], ['theme_id' => $new_theme->theme_id]);
		if ($less === true) {
			$theme = new \Core\Theme();
			$theme->get()->rebuild();

			if (defined('PHPFOX_IS_TECHIE') && PHPFOX_IS_TECHIE) {
				@copy(PHPFOX_DIR_SITE . 'flavors' . PHPFOX_DS . flavor()->active->id . PHPFOX_DS . 'flavor' . PHPFOX_DS . 'bootstrap.css', PHPFOX_DIR . 'theme' . PHPFOX_DS . 'bootstrap' . PHPFOX_DS . 'flavor' . PHPFOX_DS . 'default.css');
			}
		}
	}

	public function build_default_photos($name = null) {
		if ($name === null) $name = $this->active->id;
		$path = PHPFOX_DIR_SITE . 'flavors' . PHPFOX_DS . $name . PHPFOX_DS . 'assets' . PHPFOX_DS . 'defaults' . PHPFOX_DS;
		if (!is_dir($path)) return true;
		$id = 'flavor' . PHPFOX_DS . 'defaults' . PHPFOX_DS . $name;
		$data = [];

		foreach (scandir($path) as $file) {
			$ext = \Phpfox_File::instance()->getFileExt($file);
			if (!in_array(strtolower($ext), ['jpg', 'jpeg', 'png', 'gif'])) continue;
			$type = pathinfo($file)['filename'];
			$data[$type] = $file;
		}

		storage()->del($id);
		storage()->set($id, $data);
	}
}